From 54d5169d24d82fb7ba667698d5be07c22f228825 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 29 Apr 2016 12:30:14 -0500 Subject: [PATCH] test --- crypto777/m_unix | 6 - {iguana => deprecated}/iguana_html.c | 0 deprecated/m_unix.crypto777 | 8 + deprecated/obsolete.h | 184 ++ iguana/SuperNET.c | 2 +- iguana/exchanges/bitcoin.c | 1022 +-------- iguana/iguana.sources | 5 +- iguana/iguana777.h | 19 +- iguana/iguana_bundles.c | 29 + iguana/iguana_payments.c | 672 ++++++ iguana/iguana_realtime.c | 355 ++++ iguana/iguana_rpc.c | 4 +- iguana/iguana_sign.c | 775 +++++++ iguana/iguana_spendvectors.c | 1101 ++++++++++ iguana/iguana_txidfind.c | 609 ++++++ iguana/iguana_unspents.c | 2839 +++----------------------- iguana/iguana_volatiles.c | 342 ++++ iguana/iguana_wallet.c | 900 +++----- iguana/main.c | 2 +- iguana/ramchain_api.c | 535 +---- iguana/swaps/iguana_BTCswap.c | 10 + iguana/tests/sendmany | 1 + iguana/tests/sendtoaddress | 2 + includes/iguana_apideclares.h | 18 +- 24 files changed, 4822 insertions(+), 4618 deletions(-) rename {iguana => deprecated}/iguana_html.c (100%) create mode 100755 deprecated/m_unix.crypto777 create mode 100755 iguana/iguana_payments.c create mode 100755 iguana/iguana_realtime.c create mode 100755 iguana/iguana_sign.c create mode 100755 iguana/iguana_spendvectors.c create mode 100755 iguana/iguana_txidfind.c create mode 100755 iguana/iguana_volatiles.c create mode 100755 iguana/tests/sendmany create mode 100755 iguana/tests/sendtoaddress diff --git a/crypto777/m_unix b/crypto777/m_unix index 81891ae19..0aba4e9d5 100755 --- a/crypto777/m_unix +++ b/crypto777/m_unix @@ -1,8 +1,2 @@ -#DNN_DISABLE_GETADDRINFO_A=1 -DNN_USE_LITERAL_IFADDR=1 -DNN_HAVE_STDINT=1 -DNN_HAVE_MSG_CONTROL=1 -DNN_HAVE_SEMAPHORE=1 -DNN_HAVE_POLL=1 -DNN_HAVE_SOCKETPAIR=1 -DNN_USE_POLL=1 -#nanosrc/core/global.c nanosrc/core/ep.c nanosrc/core/epbase.c nanosrc/core/pipe.c nanosrc/core/poll.c nanosrc/core/sock.c nanosrc/core/sockbase.c nanosrc/core/symbol.c nanosrc/devices/device.c nanosrc/devices/tcpmuxd.c nanosrc/aio/ctx.c nanosrc/aio/fsm.c nanosrc/aio/poller.c nanosrc/aio/pool.c nanosrc/aio/timer.c nanosrc/aio/usock.c nanosrc/aio/timerset.c nanosrc/aio/worker.c nanosrc/utils/alloc.c nanosrc/utils/atomic.c nanosrc/utils/chunk.c nanosrc/utils/chunkref.c nanosrc/utils/clock.c nanosrc/utils/closefd.c nanosrc/utils/efd.c nanosrc/utils/err.c nanosrc/utils/glock.c nanosrc/utils/hash.c nanosrc/utils/list.c nanosrc/utils/msg.c nanosrc/utils/mutex.c nanosrc/utils/queue.c nanosrc/utils/random.c nanosrc/utils/sem.c nanosrc/utils/sleep.c nanosrc/utils/stopwatch.c nanosrc/utils/thread.c nanosrc/utils/wire.c nanosrc/protocols/utils/dist.c nanosrc/protocols/utils/excl.c nanosrc/protocols/utils/fq.c nanosrc/protocols/utils/lb.c nanosrc/protocols/utils/priolist.c nanosrc/protocols/bus/bus.c nanosrc/protocols/bus/xbus.c nanosrc/protocols/pipeline/push.c nanosrc/protocols/pipeline/pull.c nanosrc/protocols/pipeline/xpull.c nanosrc/protocols/pipeline/xpush.c nanosrc/protocols/pubsub/pub.c nanosrc/protocols/pubsub/sub.c nanosrc/protocols/pubsub/trie.c nanosrc/protocols/pubsub/xpub.c nanosrc/protocols/pubsub/xsub.c nanosrc/protocols/pair/pair.c nanosrc/protocols/pair/xpair.c nanosrc/protocols/reqrep/req.c nanosrc/protocols/reqrep/rep.c nanosrc/protocols/reqrep/task.c nanosrc/protocols/reqrep/xrep.c nanosrc/protocols/reqrep/xreq.c nanosrc/protocols/survey/respondent.c nanosrc/protocols/survey/surveyor.c nanosrc/protocols/survey/xrespondent.c nanosrc/protocols/survey/xsurveyor.c nanosrc/transports/utils/backoff.c nanosrc/transports/utils/dns.c nanosrc/transports/utils/iface.c nanosrc/transports/utils/literal.c nanosrc/transports/utils/port.c nanosrc/transports/utils/streamhdr.c nanosrc/transports/utils/base64.c nanosrc/transports/ipc/aipc.c nanosrc/transports/ipc/bipc.c nanosrc/transports/ipc/cipc.c nanosrc/transports/ipc/ipc.c nanosrc/transports/ipc/sipc.c nanosrc/transports/tcp/atcp.c nanosrc/transports/tcp/btcp.c nanosrc/transports/tcp/ctcp.c nanosrc/transports/tcp/stcp.c nanosrc/transports/tcp/tcp.c nanosrc/transports/inproc/binproc.c nanosrc/transports/inproc/cinproc.c nanosrc/transports/inproc/inproc.c nanosrc/transports/inproc/ins.c nanosrc/transports/inproc/msgqueue.c nanosrc/transports/inproc/sinproc.c - -#include crypto777.sources -#gcc -c -O2 $(CRYPTO777_SRCS) - gcc -c -O2 *.c jpeg/*.c jpeg/unix/*.c -I/usr/lib/x86_64-linux-gnu/curl rm -f ../agents/libcrypto777.a; ar rcu ../agents/libcrypto777.a *.o diff --git a/iguana/iguana_html.c b/deprecated/iguana_html.c similarity index 100% rename from iguana/iguana_html.c rename to deprecated/iguana_html.c diff --git a/deprecated/m_unix.crypto777 b/deprecated/m_unix.crypto777 new file mode 100755 index 000000000..81891ae19 --- /dev/null +++ b/deprecated/m_unix.crypto777 @@ -0,0 +1,8 @@ +#DNN_DISABLE_GETADDRINFO_A=1 -DNN_USE_LITERAL_IFADDR=1 -DNN_HAVE_STDINT=1 -DNN_HAVE_MSG_CONTROL=1 -DNN_HAVE_SEMAPHORE=1 -DNN_HAVE_POLL=1 -DNN_HAVE_SOCKETPAIR=1 -DNN_USE_POLL=1 +#nanosrc/core/global.c nanosrc/core/ep.c nanosrc/core/epbase.c nanosrc/core/pipe.c nanosrc/core/poll.c nanosrc/core/sock.c nanosrc/core/sockbase.c nanosrc/core/symbol.c nanosrc/devices/device.c nanosrc/devices/tcpmuxd.c nanosrc/aio/ctx.c nanosrc/aio/fsm.c nanosrc/aio/poller.c nanosrc/aio/pool.c nanosrc/aio/timer.c nanosrc/aio/usock.c nanosrc/aio/timerset.c nanosrc/aio/worker.c nanosrc/utils/alloc.c nanosrc/utils/atomic.c nanosrc/utils/chunk.c nanosrc/utils/chunkref.c nanosrc/utils/clock.c nanosrc/utils/closefd.c nanosrc/utils/efd.c nanosrc/utils/err.c nanosrc/utils/glock.c nanosrc/utils/hash.c nanosrc/utils/list.c nanosrc/utils/msg.c nanosrc/utils/mutex.c nanosrc/utils/queue.c nanosrc/utils/random.c nanosrc/utils/sem.c nanosrc/utils/sleep.c nanosrc/utils/stopwatch.c nanosrc/utils/thread.c nanosrc/utils/wire.c nanosrc/protocols/utils/dist.c nanosrc/protocols/utils/excl.c nanosrc/protocols/utils/fq.c nanosrc/protocols/utils/lb.c nanosrc/protocols/utils/priolist.c nanosrc/protocols/bus/bus.c nanosrc/protocols/bus/xbus.c nanosrc/protocols/pipeline/push.c nanosrc/protocols/pipeline/pull.c nanosrc/protocols/pipeline/xpull.c nanosrc/protocols/pipeline/xpush.c nanosrc/protocols/pubsub/pub.c nanosrc/protocols/pubsub/sub.c nanosrc/protocols/pubsub/trie.c nanosrc/protocols/pubsub/xpub.c nanosrc/protocols/pubsub/xsub.c nanosrc/protocols/pair/pair.c nanosrc/protocols/pair/xpair.c nanosrc/protocols/reqrep/req.c nanosrc/protocols/reqrep/rep.c nanosrc/protocols/reqrep/task.c nanosrc/protocols/reqrep/xrep.c nanosrc/protocols/reqrep/xreq.c nanosrc/protocols/survey/respondent.c nanosrc/protocols/survey/surveyor.c nanosrc/protocols/survey/xrespondent.c nanosrc/protocols/survey/xsurveyor.c nanosrc/transports/utils/backoff.c nanosrc/transports/utils/dns.c nanosrc/transports/utils/iface.c nanosrc/transports/utils/literal.c nanosrc/transports/utils/port.c nanosrc/transports/utils/streamhdr.c nanosrc/transports/utils/base64.c nanosrc/transports/ipc/aipc.c nanosrc/transports/ipc/bipc.c nanosrc/transports/ipc/cipc.c nanosrc/transports/ipc/ipc.c nanosrc/transports/ipc/sipc.c nanosrc/transports/tcp/atcp.c nanosrc/transports/tcp/btcp.c nanosrc/transports/tcp/ctcp.c nanosrc/transports/tcp/stcp.c nanosrc/transports/tcp/tcp.c nanosrc/transports/inproc/binproc.c nanosrc/transports/inproc/cinproc.c nanosrc/transports/inproc/inproc.c nanosrc/transports/inproc/ins.c nanosrc/transports/inproc/msgqueue.c nanosrc/transports/inproc/sinproc.c + +#include crypto777.sources +#gcc -c -O2 $(CRYPTO777_SRCS) + +gcc -c -O2 *.c jpeg/*.c jpeg/unix/*.c -I/usr/lib/x86_64-linux-gnu/curl +rm -f ../agents/libcrypto777.a; ar rcu ../agents/libcrypto777.a *.o diff --git a/deprecated/obsolete.h b/deprecated/obsolete.h index c231ad9ba..2c667ebc2 100755 --- a/deprecated/obsolete.h +++ b/deprecated/obsolete.h @@ -16260,6 +16260,190 @@ len = 0; } else return(clonestr("{\"error\":\"couldnt save wallet backup\"}")); } + /*struct iguana_waddress *iguana_waccountadd(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount **wacctp,char *walletaccount,char *coinaddr,char *redeemScript) + { + struct iguana_waccount *wacct; struct iguana_waddress *waddr = 0; + if ( (wacct= iguana_waccountfind(myinfo,coin,walletaccount)) == 0 ) + wacct = iguana_waccountcreate(myinfo,coin,walletaccount); + if ( wacct != 0 ) + waddr = iguana_waddresscreate(myinfo,coin,wacct,coinaddr,redeemScript); + return(waddr); + }*/ +#ifdef testing + char *bitcoin_cltvtx(struct iguana_info *coin,char *changeaddr,char *senderaddr,char *senders_otheraddr,char *otheraddr,uint32_t locktime,uint64_t satoshis,bits256 txid,int32_t vout,uint64_t inputsatoshis,bits256 privkey) + { + uint64_t change; char *rawtxstr,*signedtx; struct vin_info V; bits256 cltxid,signedtxid; + int32_t cltvlen,len; uint32_t timestamp; char ps2h_coinaddr[65]; cJSON *txobj; + uint8_t p2sh_rmd160[20],cltvscript[1024],paymentscript[64],rmd160[20],secret160[20],addrtype; + timestamp = (uint32_t)time(NULL); + bitcoin_addr2rmd160(&addrtype,secret160,senders_otheraddr); + cltvlen = bitcoin_cltvscript(coin->chain->p2shtype,ps2h_coinaddr,p2sh_rmd160,cltvscript,0,senderaddr,otheraddr,secret160,locktime); + txobj = bitcoin_createtx(coin,locktime); + len = bitcoin_p2shspend(paymentscript,0,p2sh_rmd160); + bitcoin_addoutput(coin,txobj,paymentscript,len,satoshis); + bitcoin_addinput(coin,txobj,txid,vout,locktime); + if ( inputsatoshis > (satoshis + 10000) ) + { + change = inputsatoshis - (satoshis + 10000); + if ( changeaddr != 0 && changeaddr[0] != 0 ) + { + bitcoin_addr2rmd160(&addrtype,rmd160,changeaddr); + if ( addrtype == coin->chain->pubtype ) + len = bitcoin_standardspend(paymentscript,0,rmd160); + else if ( addrtype == coin->chain->p2shtype ) + len = bitcoin_standardspend(paymentscript,0,rmd160); + else + { + printf("error with mismatched addrtype.%02x vs (%02x %02x)\n",addrtype,coin->chain->pubtype,coin->chain->p2shtype); + return(0); + } + bitcoin_addoutput(coin,txobj,paymentscript,len,change); + } + else + { + printf("error no change address when there is change\n"); + return(0); + } + } + rawtxstr = bitcoin_json2hex(coin,&cltxid,txobj); + char str[65]; printf("CLTV.%s (%s)\n",bits256_str(str,cltxid),rawtxstr); + memset(&V,0,sizeof(V)); + V.signers[0].privkey = privkey; + bitcoin_verifytx(coin,&signedtxid,&signedtx,rawtxstr,&V); + free(rawtxstr); + if ( signedtx != 0 ) + printf("signed CLTV.%s (%s)\n",bits256_str(str,signedtxid),signedtx); + else printf("error generating signedtx\n"); + free_json(txobj); + return(signedtx); + } +#endif + + char *refstr = "01000000\ + 01\ + eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2\ + 01000000\ + 8c\ + 4930460221009e0339f72c793a89e664a8a932df073962a3f84eda0bd9e02084a6a9567f75aa022100bd9cbaca2e5ec195751efdfac164b76250b1e21302e51ca86dd7ebd7020cdc0601410450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6\ + ffffffff\ + 01\ + 605af40500000000\ + 19\ + 76a914097072524438d003d23a2f23edb65aae1bb3e46988ac\ + 00000000"; + + cJSON *bitcoin_txtest(struct iguana_info *coin,char *rawtxstr,bits256 txid) + { + struct iguana_msgtx msgtx; char str[65],str2[65]; bits256 checktxid,blockhash,signedtxid; + cJSON *retjson,*txjson; uint8_t *serialized,*serialized2; uint32_t firstvout; + struct vin_info *V; char vpnstr[64],*txbytes,*signedtx; int32_t n,txstart,height,n2,maxsize,len; + rawtxstr = refstr; + len = (int32_t)strlen(rawtxstr); + maxsize = len + 32768; + serialized = calloc(1,maxsize); + serialized2 = calloc(1,maxsize); + len >>= 1; + V = 0; + vpnstr[0] = 0; + memset(&msgtx,0,sizeof(msgtx)); + if ( len < maxsize ) + { + decode_hex(serialized,len,rawtxstr); + txjson = cJSON_CreateObject(); + retjson = cJSON_CreateObject(); + if ( (n= iguana_rwmsgtx(coin,0,txjson,serialized,maxsize,&msgtx,&txid,vpnstr)) < 0 ) + { + printf("bitcoin_txtest len.%d: n.%d from (%s)\n",len,n,rawtxstr); + free(serialized), free(serialized2); + return(cJSON_Parse("{\"error\":\"cant parse txbytes\"}")); + } + V = calloc(msgtx.tx_in,sizeof(*V)); + { + //char *pstr; int32_t plen; + decode_hex(V[0].signers[0].privkey.bytes,sizeof(V[0].signers[0].privkey),"18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725"); + //pstr = "0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6"; + //plen = (int32_t)strlen(pstr); + //decode_hex(V[0].signers[0].pubkey,plen,pstr); + } + if ( bitcoin_verifytx(coin,&signedtxid,&signedtx,rawtxstr,V) != 0 ) + printf("bitcoin_verifytx error\n"); + jadd(retjson,"result",txjson); + if ( (firstvout= iguana_unspentindfind(coin,&height,txid,0,coin->bundlescount-1)) != 0 ) + { + if ( height >= 0 ) + { + blockhash = iguana_blockhash(coin,height); + jaddnum(retjson,"height",height); + jaddnum(retjson,"confirmations",coin->longestchain - height); + jaddbits256(retjson,"blockhash",blockhash); + } + } + //printf("retjson.(%s) %p\n",jprint(retjson,0),retjson); + memset(checktxid.bytes,0,sizeof(checktxid)); + if ( (n2= iguana_rwmsgtx(coin,1,0,serialized2,maxsize,&msgtx,&checktxid,vpnstr)) < 0 || n != n2 ) + { + printf("bitcoin_txtest: n.%d vs n2.%d\n",n,n2); + free(serialized), free(serialized2), free(V); + return(retjson); + } + if ( bits256_cmp(checktxid,txid) != 0 ) + { + printf("bitcoin_txtest: txid.%s vs check.%s\n",bits256_str(str,txid),bits256_str(str2,checktxid)); + } + checktxid = iguana_parsetxobj(coin,&txstart,serialized,maxsize,&msgtx,jobj(retjson,"result")); + if ( bits256_cmp(checktxid,txid) != 0 ) + { + printf("bitcoin_txtest: txid.%s vs check2.%s\n",bits256_str(str,txid),bits256_str(str2,checktxid)); + } + if ( msgtx.allocsize != 0 ) + { + txbytes = malloc(msgtx.allocsize*2 + 1); + init_hexbytes_noT(txbytes,&serialized[txstart],msgtx.allocsize); + if ( strcmp(txbytes,rawtxstr) != 0 ) + printf("bitcoin_txtest: reconstruction error: %s != %s\n",rawtxstr,txbytes); + else printf("reconstruction PASSED\n"); + free(txbytes); + } else printf("bitcoin_txtest: zero msgtx allocsize\n"); + free(serialized), free(serialized2), free(V); + return(retjson); + } + free(serialized), free(serialized2); + return(cJSON_Parse("{\"error\":\"testing bitcoin txbytes\"}")); + } + + + /*int32_t btc_priv2wif(char *wifstr,uint8_t privkey[32],uint8_t addrtype) + { + uint8_t tmp[128]; char hexstr[67]; cstring *btc_addr; + memcpy(tmp,privkey,32); + tmp[32] = 1; + init_hexbytes_noT(hexstr,tmp,32); + if ( (btc_addr= base58_encode_check(addrtype,true,tmp,33)) != 0 ) + { + strcpy(wifstr,btc_addr->str); + cstr_free(btc_addr,true); + } + //printf("-> (%s) -> wif.(%s) addrtype.%02x\n",hexstr,wifstr,addrtype); + return(0); + } + + cstring *base58_encode_check(uint8_t addrtype,bool have_addrtype,const void *data,size_t data_len) + { + uint8_t i,buf[64]; bits256 hash; cstring *s_enc;//,*s = cstr_new_sz(data_len + 1 + 4); + buf[0] = addrtype; + memcpy(buf+1,data,data_len); + hash = bits256_doublesha256(0,buf,(int32_t)data_len+1); + //bu_Hash4(md32,buf,(int32_t)data_len+1); + for (i=0; i<4; i++) + { + buf[data_len+i+1] = hash.bytes[31-i]; + //printf("(%02x %02x) ",hash.bytes[31-i],md32[i]); + } + //printf("hash4 cmp\n"); + s_enc = base58_encode(buf,data_len+5); + return s_enc; + } + */ #endif #endif diff --git a/iguana/SuperNET.c b/iguana/SuperNET.c index a2918adf8..8799dab9c 100755 --- a/iguana/SuperNET.c +++ b/iguana/SuperNET.c @@ -1407,7 +1407,7 @@ FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase) { SuperNET_setkeys(myinfo,passphrase,(int32_t)strlen(passphrase),1); free_json(argjson); - myinfo->expiration = (uint32_t)(time(NULL) + 3600*24); + myinfo->expiration = (uint32_t)(time(NULL) + 3600); return(SuperNET_activehandle(IGUANA_CALLARGS)); } else diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index 57cc788d4..b92617288 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -14,6 +14,7 @@ ******************************************************************************/ #include "bitcoin.h" + cJSON *instantdex_statemachinejson(struct bitcoin_swapinfo *swap); char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params) @@ -97,39 +98,6 @@ int32_t bitcoin_validaddress(struct iguana_info *coin,char *coinaddr) return(0); } -/*int32_t btc_priv2wif(char *wifstr,uint8_t privkey[32],uint8_t addrtype) -{ - uint8_t tmp[128]; char hexstr[67]; cstring *btc_addr; - memcpy(tmp,privkey,32); - tmp[32] = 1; - init_hexbytes_noT(hexstr,tmp,32); - if ( (btc_addr= base58_encode_check(addrtype,true,tmp,33)) != 0 ) - { - strcpy(wifstr,btc_addr->str); - cstr_free(btc_addr,true); - } - //printf("-> (%s) -> wif.(%s) addrtype.%02x\n",hexstr,wifstr,addrtype); - return(0); -} - -cstring *base58_encode_check(uint8_t addrtype,bool have_addrtype,const void *data,size_t data_len) -{ - uint8_t i,buf[64]; bits256 hash; cstring *s_enc;//,*s = cstr_new_sz(data_len + 1 + 4); - buf[0] = addrtype; - memcpy(buf+1,data,data_len); - hash = bits256_doublesha256(0,buf,(int32_t)data_len+1); - //bu_Hash4(md32,buf,(int32_t)data_len+1); - for (i=0; i<4; i++) - { - buf[data_len+i+1] = hash.bytes[31-i]; - //printf("(%02x %02x) ",hash.bytes[31-i],md32[i]); - } - //printf("hash4 cmp\n"); - s_enc = base58_encode(buf,data_len+5); - return s_enc; -} -*/ - int32_t base58encode_checkbuf(uint8_t addrtype,uint8_t *data,int32_t data_len) { uint8_t i; bits256 hash; @@ -164,7 +132,7 @@ int32_t bitcoin_priv2wif(char *wifstr,bits256 privkey,uint8_t addrtype) memcpy(data+1,privkey.bytes,sizeof(privkey)); data[33] = 1; len = base58encode_checkbuf(addrtype,data,33); - + if ( bitcoin_base58encode(wifstr,data,len) == 0 ) return(-1); if ( 1 ) @@ -179,619 +147,86 @@ int32_t bitcoin_priv2wif(char *wifstr,bits256 privkey,uint8_t addrtype) return((int32_t)strlen(wifstr)); } -int32_t iguana_parsevoutobj(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvout *vout,cJSON *voutobj) -{ - int32_t len = 0; cJSON *skey; char *hexstr; - memset(vout,0,sizeof(*vout)); - vout->value = jdouble(voutobj,"value") * SATOSHIDEN; - if ( (skey= jobj(voutobj,"scriptPubKey")) != 0 ) - { - if ( (hexstr= jstr(skey,"hex")) != 0 ) - { - len = (int32_t)strlen(hexstr) >> 1; - decode_hex(serialized,len,hexstr); - vout->pk_script = serialized; - vout->pk_scriptlen = len; - } - } - return(len); -} - -int32_t iguana_parsevinobj(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvin *vin,cJSON *vinobj) -{ - int32_t n,len = 0; char *hexstr,*spendstr = 0; cJSON *scriptjson; - memset(vin,0,sizeof(*vin)); - vin->prev_vout = -1; - vin->sequence = juint(vinobj,"sequence"); - if ( (hexstr= jstr(vinobj,"coinbase")) == 0 ) - { - vin->prev_hash = jbits256(vinobj,"txid"); - vin->prev_vout = jint(vinobj,"vout"); - if ( (scriptjson= jobj(vinobj,"scriptSig")) != 0 ) - hexstr = jstr(scriptjson,"hex"); - if ( (scriptjson= jobj(vinobj,"scriptPub")) != 0 ) - spendstr = jstr(scriptjson,"hex"); - } - if ( hexstr != 0 ) - { - len = (int32_t)strlen(hexstr) >> 1; - decode_hex(serialized,len,hexstr); - vin->vinscript = serialized; - vin->scriptlen = len; - serialized = &serialized[len]; - } //else printf("iguana_parsevinobj: hex script missing (%s)\n",jprint(vinobj,0)); - if ( spendstr != 0 ) - { - n = (int32_t)strlen(spendstr) >> 1; - decode_hex(serialized,n,spendstr); - vin->spendscript = serialized; - vin->spendlen = n; - len += n; - } - return(len); -} - -cJSON *iguana_voutjson(struct iguana_info *coin,struct iguana_msgvout *vout,int32_t txi,bits256 txid) -{ - // 035f1321ed17d387e4433b2fa229c53616057964af065f98bfcae2233c5108055e OP_CHECKSIG - char scriptstr[IGUANA_MAXSCRIPTSIZE+1],asmstr[2*IGUANA_MAXSCRIPTSIZE+1]; int32_t i,m,n,scriptlen,asmtype; struct vin_info *vp; - uint8_t space[8192]; cJSON *addrs,*skey,*json = cJSON_CreateObject(); - vp = calloc(1,sizeof(*vp)); - jaddnum(json,"value",dstr(vout->value)); - jaddnum(json,"n",txi); - //"scriptPubKey":{"asm":"OP_DUP OP_HASH160 5f69cb73016264270dae9f65c51f60d0e4d6fd44 OP_EQUALVERIFY OP_CHECKSIG","reqSigs":1,"type":"pubkeyhash","addresses":["RHyh1V9syARTf2pyxibz7v27D5paBeWza5"]} - if ( vout->pk_script != 0 && vout->pk_scriptlen*2+1 < sizeof(scriptstr) ) - { - memset(vp,0,sizeof(*vp)); - if ( (asmtype= iguana_calcrmd160(coin,asmstr,vp,vout->pk_script,vout->pk_scriptlen,txid,txi,0xffffffff)) >= 0 ) - { - skey = cJSON_CreateObject(); - scriptlen = iguana_scriptgen(coin,&m,&n,vp->coinaddr,space,asmstr,vp->rmd160,asmtype,vp,txi); - if ( asmstr[0] != 0 ) - jaddstr(skey,"asm",asmstr); - addrs = cJSON_CreateArray(); - if ( vp->N == 1 ) - { - if ( asmtype == 2 ) - { - jaddnum(skey,"reqSigs",1); - jaddstr(skey,"type","pubkeyhash"); - } - if ( vp->coinaddr[0] != 0 ) - jaddistr(addrs,vp->coinaddr); - } - else - { - jaddnum(skey,"reqSigs",vp->M); - for (i=0; iN; i++) - { - //btc_convrmd160(coinaddr,coin->chain->pubtype,V.signers[i].pubkey); - jaddistr(addrs,vp->signers[i].coinaddr); - } - } - jadd(skey,"addresses",addrs); - init_hexbytes_noT(scriptstr,vout->pk_script,vout->pk_scriptlen); - if ( scriptstr[0] != 0 ) - jaddstr(skey,"hex",scriptstr); - jadd(json,"scriptPubKey",skey); - } - } - return(json); -} - -void iguana_addscript(struct iguana_info *coin,cJSON *dest,uint8_t *script,int32_t scriptlen,char *fieldname) -{ - char *scriptstr,scriptbuf[8192+256]; int32_t len; cJSON *scriptobj; - if ( scriptlen < 0 ) - return; - if ( scriptlen > sizeof(scriptbuf) ) - len = (scriptlen << 1) + 256, scriptstr = malloc(len); - else scriptstr = scriptbuf, len = sizeof(scriptbuf); - init_hexbytes_noT(scriptstr,script,scriptlen); - if ( strcmp(fieldname,"coinbase") == 0 ) - jaddstr(dest,"coinbase",scriptstr); - else - { - scriptobj = cJSON_CreateObject(); - jaddstr(scriptobj,"hex",scriptstr); - iguana_expandscript(coin,scriptstr,len,script,scriptlen); - if ( scriptstr[0] != 0 ) - jaddstr(scriptobj,"asm",scriptstr); - if ( scriptstr != scriptbuf ) - free(scriptstr); - jadd(dest,fieldname,scriptobj); - } -} - -cJSON *iguana_vinjson(struct iguana_info *coin,struct iguana_msgvin *vin) -{ - char str[65]; int32_t vout; cJSON *json = cJSON_CreateObject(); - vout = vin->prev_vout; - jaddnum(json,"sequence",vin->sequence); - if ( vout < 0 && bits256_nonz(vin->prev_hash) == 0 ) - iguana_addscript(coin,json,vin->vinscript,vin->scriptlen,"coinbase"); - else - { - jaddstr(json,"txid",bits256_str(str,vin->prev_hash)); - jaddnum(json,"vout",vout); - if ( vin->scriptlen > 0 ) - iguana_addscript(coin,json,vin->vinscript,vin->scriptlen,"scriptSig"); - if ( vin->spendlen > 0 ) - iguana_addscript(coin,json,vin->spendscript,vin->spendlen,"scriptPub"); - } - return(json); -} - -int32_t iguana_vinparse(struct iguana_info *coin,int32_t rwflag,uint8_t *serialized,struct iguana_msgvin *msg) -{ - int32_t len = 0; - len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->prev_hash),msg->prev_hash.bytes); - len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout); - len += iguana_rwvarint32(rwflag,&serialized[len],&msg->scriptlen); - if ( msg->scriptlen > IGUANA_MAXSCRIPTSIZE ) - { - printf("iguana_vinparse illegal scriptlen.%d\n",msg->scriptlen); - return(-1); - } - if ( rwflag == 0 ) - { - msg->vinscript = &serialized[len]; - len += msg->scriptlen; - } - else - { - if ( msg->scriptlen > 0 ) - { - memcpy(&serialized[len],msg->vinscript,msg->scriptlen); - len += msg->scriptlen; - } - } - len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence); - if ( 0 ) - { - int32_t i; char str[65]; - for (i=0; iscriptlen; i++) - printf("%02x",msg->vinscript[i]); - printf(" prev_hash.(%s) vout.%d [%p] scriptlen.%d rwflag.%d\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->vinscript,msg->scriptlen,rwflag); - } - return(len); -} - -int32_t iguana_voutparse(int32_t rwflag,uint8_t *serialized,struct iguana_msgvout *msg) -{ - int32_t len = 0; - len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->value),&msg->value); - len += iguana_rwvarint32(rwflag,&serialized[len],&msg->pk_scriptlen); - if ( msg->pk_scriptlen > IGUANA_MAXSCRIPTSIZE ) - { - printf("iguana_voutparse illegal scriptlen.%d\n",msg->pk_scriptlen); - return(-1); - } - if ( rwflag == 0 ) - msg->pk_script = &serialized[len]; - else memcpy(&serialized[len],msg->pk_script,msg->pk_scriptlen); - if ( 0 ) - { - int32_t i; - for (i=0; ipk_scriptlen; i++) - printf("%02x",msg->pk_script[i]); - printf(" [%p] scriptlen.%d rwflag.%d %.8f\n",msg->pk_script,msg->pk_scriptlen,rwflag,dstr(msg->value)); - } - len += msg->pk_scriptlen; - return(len); -} - -// {"result":{"txid":"867ab5071349ef8d0dcd03a43017b6b440c9533cb26a8a6870127e7884ff96f6","version":1,"time":1404960685,"locktime":0,"vin":[{"coinbase":"510103","sequence":4294967295}],"vout":[{"value":80.00000000,"n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 5f69cb73016264270dae9f65c51f60d0e4d6fd44 OP_EQUALVERIFY OP_CHECKSIG","reqSigs":1,"type":"pubkeyhash","addresses":["RHyh1V9syARTf2pyxibz7v27D5paBeWza5"]}}],"blockhash":"000000000c4682089c916de89eb080a877566494d4009c0089baf35fe94de22f","confirmations":930039} -//{"version":1,"timestamp":1404960685,"vins":[{"sequence":4294967295,"coinbase":"510103"}],"numvins":1,"vouts":[{"value":80,"n":0,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 5f69cb73016264270dae9f65c51f60d0e4d6fd44 OP_EQUALVERIFY OP_CHECKSIG","reqSigs":1,"type":"pubkeyhash","addrs":["RHyh1V9syARTf2pyxibz7v27D5paBeWza5"],"hex":"76a9145f69cb73016264270dae9f65c51f60d0e4d6fd4488ac"}}],"numvouts":1,"locktime":0,"size":92,"txid":"867ab5071349ef8d0dcd03a43017b6b440c9533cb26a8a6870127e7884ff96f6","tag":"3968374231439324584"} - -int32_t iguana_rwmsgtx(struct iguana_info *coin,int32_t rwflag,cJSON *json,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,bits256 *txidp,char *vpnstr) +int32_t iguana_validatesigs(struct iguana_info *coin,struct iguana_msgvin *vin) { - int32_t i,n,len = 0; uint8_t *txstart = serialized; char txidstr[65]; cJSON *array=0; - len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->version),&msg->version); - if ( json != 0 ) - { - jaddnum(json,"version",msg->version); - array = cJSON_CreateArray(); - } - //printf("version.%d\n",msg->version); - if ( coin->chain->hastimestamp != 0 ) - { - len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->timestamp),&msg->timestamp); - //char str[65]; printf("version.%d timestamp.%08x %u %s\n",msg->version,msg->timestamp,msg->timestamp,utc_str(str,msg->timestamp)); - if ( json != 0 ) - jaddnum(json,"timestamp",msg->timestamp); - } - //for (i=len; itx_in); - //printf(" tx_in.%08x\n",msg->tx_in); - if ( rwflag == 0 ) - { - if ( len + sizeof(struct iguana_msgvin)*msg->tx_in > maxsize ) - { - printf("len.%d + tx_in.%d > maxsize.%d\n",len,msg->tx_in,maxsize); - return(-1); - } - maxsize -= (sizeof(struct iguana_msgvin) * msg->tx_in); - msg->vins = (struct iguana_msgvin *)&serialized[maxsize]; - memset(msg->vins,0,sizeof(struct iguana_msgvin) * msg->tx_in); - } - for (i=0; itx_in; i++) - { - if ( (n= iguana_vinparse(coin,rwflag,&serialized[len],&msg->vins[i])) < 0 ) - return(-1); - //printf("vin.%d n.%d len.%d\n",i,n,len); - len += n; - if ( len > maxsize ) - { - printf("invalid tx_in.%d len.%d vs maxsize.%d\n",msg->tx_in,len,maxsize); - return(-1); - } - if ( array != 0 ) - jaddi(array,iguana_vinjson(coin,&msg->vins[i])); - } - if ( array != 0 ) - { - jadd(json,"vin",array); - jaddnum(json,"numvins",msg->tx_in); - array = cJSON_CreateArray(); - } - //for (i=len; itx_out); - //printf(" txout.%d\n",msg->tx_out); - if ( rwflag == 0 ) - { - if ( len + sizeof(struct iguana_msgvout)*msg->tx_out > maxsize ) - { - printf("len.%d + tx_in.%d > maxsize.%d\n",len,msg->tx_in,maxsize); - return(-1); - } - maxsize -= (sizeof(struct iguana_msgvout) * msg->tx_out); - msg->vouts = (struct iguana_msgvout *)&serialized[maxsize]; - memset(msg->vouts,0,sizeof(struct iguana_msgvout) * msg->tx_out); - } - for (i=0; itx_out; i++) - { - if ( (n= iguana_voutparse(rwflag,&serialized[len],&msg->vouts[i])) < 0 ) - return(-1); - len += n; - if ( len > maxsize ) - { - printf("invalid tx_out.%d len.%d vs maxsize.%d\n",msg->tx_out,len,maxsize); - return(-1); - } - if ( array != 0 ) - jaddi(array,iguana_voutjson(coin,&msg->vouts[i],i,*txidp)); - } - if ( array != 0 ) - { - jadd(json,"vout",array); - jaddnum(json,"numvouts",msg->tx_out); - } - len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->lock_time),&msg->lock_time); - //printf("lock_time.%08x\n",msg->lock_time); - if ( strcmp(coin->symbol,"VPN") == 0 ) - { - uint16_t ddosflag = 0; - len += iguana_rwnum(rwflag,&serialized[len],sizeof(ddosflag),&ddosflag); - for (i=0; serialized[len]!=0&&lenlock_time); - jaddnum(json,"size",len); - jaddbits256(json,"txid",*txidp); - //printf("TX.(%s) %p\n",jprint(json,0),json); - } - msg->allocsize = len; - return(len); + // multiple coins + // ro -> vouts collision, purgeable + // + return(0); } -bits256 iguana_parsetxobj(struct iguana_info *coin,int32_t *txstartp,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,cJSON *txobj) // json -> serialized + (msg,V) +uint64_t bitcoin_parseunspent(struct iguana_info *coin,struct bitcoin_unspent *unspent,double minconfirms,char *account,cJSON *item) { - int32_t i,numvins,numvouts,len = 0; cJSON *array=0; bits256 txid; char vpnstr[64]; - memset(msg,0,sizeof(*msg)); - vpnstr[0] = 0; - if ( (msg->version= juint(txobj,"version")) == 0 ) - msg->version = 1; - if ( coin->chain->hastimestamp != 0 ) - { - if ( (msg->timestamp= juint(txobj,"timestamp")) == 0 ) - msg->timestamp = (uint32_t)time(NULL); - } - if ( (array= jarray(&numvins,txobj,"vin")) != 0 ) + uint8_t addrtype; char *hexstr,*wifstr,coinaddr[64],args[128]; + memset(unspent,0,sizeof(*unspent)); + if ( jstr(item,"address") != 0 ) { - msg->tx_in = numvins; - if ( len + sizeof(struct iguana_msgvin)*msg->tx_in > maxsize ) - return(msg->txid); - maxsize -= (sizeof(struct iguana_msgvin) * msg->tx_in); - msg->vins = (struct iguana_msgvin *)&serialized[maxsize]; - if ( msg->tx_in > 0 && msg->tx_in*sizeof(struct iguana_msgvin) < maxsize ) + safecopy(coinaddr,jstr(item,"address"),sizeof(coinaddr)); + bitcoin_addr2rmd160(&unspent->addrtype,unspent->rmd160,coinaddr); + sprintf(args,"[\"%s\"]",coinaddr); + wifstr = bitcoind_RPC(0,coin->symbol,coin->chain->serverport,coin->chain->userpass,"dumpprivkey",args); + if ( wifstr != 0 ) { - for (i=0; itx_in; i++) - len += iguana_parsevinobj(coin,&serialized[len],maxsize,&msg->vins[i],jitem(array,i)); - } + bitcoin_wif2priv(&addrtype,&unspent->privkeys[0],wifstr); + //printf("wifstr.(%s) -> %s\n",wifstr,bits256_str(str,unspent->privkeys[0])); + free(wifstr); + } else fprintf(stderr,"error (%s) cant find privkey\n",coinaddr); } - if ( (array= jarray(&numvouts,txobj,"vout")) != 0 ) + if ( (account == 0 || jstr(item,"account") == 0 || strcmp(account,jstr(item,"account")) == 0) && (minconfirms <= 0 || juint(item,"confirmations") >= minconfirms-SMALLVAL) ) { - msg->tx_out = numvouts; - if ( len + sizeof(struct iguana_msgvout)*msg->tx_out > maxsize ) - return(msg->txid); - maxsize -= (sizeof(struct iguana_msgvout) * msg->tx_out); - msg->vouts = (struct iguana_msgvout *)&serialized[maxsize]; - if ( msg->tx_out > 0 && msg->tx_out*sizeof(struct iguana_msgvout) < maxsize ) + if ( (hexstr= jstr(item,"scriptPubKey")) != 0 ) { - for (i=0; itx_out; i++) - len += iguana_parsevoutobj(coin,&serialized[len],maxsize,&msg->vouts[i],jitem(array,i)); + unspent->spendlen = (int32_t)strlen(hexstr) >> 1; + if ( unspent->spendlen < sizeof(unspent->spendscript) ) + decode_hex(unspent->spendscript,unspent->spendlen,hexstr); } - } - msg->lock_time = juint(txobj,"locktime"); - msg->txid = jbits256(txobj,"txid"); - *txstartp = len; - if ( (msg->allocsize= iguana_rwmsgtx(coin,1,0,&serialized[len],maxsize-len,msg,&txid,vpnstr)) < 0 ) - { - memset(txid.bytes,0,sizeof(txid)); - printf("error parsing txobj\n"); - msg->allocsize = 0; - } - //char str[65]; printf("json -> %s\n",bits256_str(str,txid)); - return(txid); -} - -char *iguana_rawtxbytes(struct iguana_info *coin,cJSON *json,struct iguana_msgtx *msgtx) -{ - int32_t n; char *txbytes = 0,vpnstr[64]; uint8_t *serialized; - serialized = malloc(IGUANA_MAXPACKETSIZE); - vpnstr[0] = 0; - //char str[65]; printf("%d of %d: %s\n",i,msg.txn_count,bits256_str(str,tx.txid)); - if ( (n= iguana_rwmsgtx(coin,1,json,serialized,IGUANA_MAXPACKETSIZE,msgtx,&msgtx->txid,vpnstr)) > 0 ) - { - txbytes = malloc(n*2+1); - init_hexbytes_noT(txbytes,serialized,n); - } - free(serialized); - return(txbytes); + unspent->txid = jbits256(item,"txid"); + unspent->value = SATOSHIDEN * jdouble(item,"amount"); + unspent->vout = jint(item,"vout"); + //char str[65]; printf("(%s) -> %s %.8f scriptlen.%d\n",jprint(item,0),bits256_str(str,unspent->txid),dstr(unspent->value),unspent->scriptlen); + } else printf("skip.(%s) minconfirms.%f\n",jprint(item,0),minconfirms); + return(unspent->value); } -int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighashsingle) +struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,char **retstrp,double *balancep,int32_t *numunspentsp,double minconfirms,char *account) { - bits256 txid,sigtxid,revsigtxid; uint8_t *sig,*pubkey; struct vin_info *vp; - char txidstr[128],bigstr[2560],coinaddr[64],vpnstr[64],str[65]; uint32_t suffixlen,sigsize,pubkeysize; - int32_t n2,i,j,k,plen,vini=0,flag,numvins,hashtype,retval,siglen,asmtype,numvouts; - numvouts = msgtx->tx_out; - vpnstr[0] = 0; - *signedtx = 0; - memset(signedtxidp,0,sizeof(*signedtxidp)); - numvins = msgtx->tx_in; - retval = -numvins; - for (vini=0; vinisymbol,coin->chain->serverport,coin->chain->userpass,"listunspent",params)) != 0 ) { - //saveinput = msgtx->vins[vini].vinscript; - vp = &V[vini]; - sig = &msgtx->vins[vini].vinscript[1]; - siglen = msgtx->vins[vini].vinscript[0]; - vp->vin = msgtx->vins[vini]; - flag = 0; - for (k=0; k<2; k++) + //printf("sss unspents.(%s)\n",retstr); + if ( (utxo= cJSON_Parse(retstr)) != 0 ) { - asmtype = (k == 0) ? IGUANA_SCRIPT_76A988AC : IGUANA_SCRIPT_76AC; - if ( bitcoin_scriptget(coin,&hashtype,&sigsize,&pubkeysize,&suffixlen,vp,msgtx->vins[vini].vinscript,msgtx->vins[vini].scriptlen,asmtype) < 0 ) - { - printf("cant get script for (%s).v%d\n",bits256_str(str,vp->vin.prev_hash),vp->vin.prev_vout); - continue; - } - if ( sighashsingle != 0 && vini == 0 ) - { - msgtx->tx_out = 1; - hashtype = SIGHASH_SINGLE; - } else msgtx->tx_out = numvouts; - msgtx->vins[vini].spendscript = vp->spendscript; - msgtx->vins[vini].spendlen = vp->spendlen; - msgtx->vins[vini].sequence = vp->sequence; - for (j=0; jN; j++) + n = 0; + if ( (*numunspentsp= cJSON_GetArraySize(utxo)) > 0 ) { - pubkey = vp->signers[j].pubkey; - if ( (plen= bitcoin_pubkeylen(pubkey)) < 0 ) + unspents = calloc(*numunspentsp,sizeof(*unspents)); + for (i=0; i<*numunspentsp; i++) { - if ( bits256_nonz(vp->signers[j].privkey) > 0 ) - { - pubkey = vp->signers[j].pubkey; - bitcoin_pubkey33(pubkey,vp->signers[j].privkey); - plen = bitcoin_pubkeylen(pubkey); - } - if ( plen < 0 ) + value = bitcoin_parseunspent(coin,&unspents[n],minconfirms,account,jitem(utxo,i)); + //printf("i.%d n.%d value %.8f\n",i,n,dstr(value)); + if ( value != 0 ) { - printf("nopubkey for j.%d vini.%d plen.%d [%02x]\n",j,vini,plen,pubkey[0]); - continue; + total += value; + n++; } } - bitcoin_address(coinaddr,coin->chain->pubtype,pubkey,plen); - n2 = iguana_rwmsgtx(coin,1,0,serialized,maxsize,msgtx,&txid,vpnstr); - if ( n2 > 0 ) - { - n2 += iguana_rwnum(1,&serialized[n2],sizeof(hashtype),&hashtype); - //printf("hashtype.%d [%02x]\n",hashtype,sig[siglen-1]); - revsigtxid = bits256_doublesha256(txidstr,serialized,n2); - for (i=0; isigners[j].privkey) != 0 ) - { - siglen = bitcoin_sign(vp->signers[j].sig,sizeof(vp->signers[j].sig),sigtxid.bytes,sizeof(sigtxid),vp->signers[j].privkey); - sig = vp->signers[j].sig; - sig[siglen++] = hashtype; - vp->signers[j].siglen = siglen; - msgtx->vins[vini].vinscript = calloc(1,siglen*2+256); // fix this memleak! - msgtx->vins[vini].scriptlen = bitcoin_scriptsig(coin,msgtx->vins[vini].vinscript,0,(const struct vin_info *)vp,msgtx); - //for (i=0; isigners[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) - { - init_hexbytes_noT(bigstr,serialized,n2); - printf("(%s) doesnt verify hash2.%s\n",bigstr,bits256_str(str,sigtxid)); - *signedtx = iguana_rawtxbytes(coin,0,msgtx); - *signedtxidp = msgtx->txid; - printf("SIG.%d ERROR %s\n",vini,*signedtx); - } - else - { - cJSON *txobj = cJSON_CreateObject(); - *signedtx = iguana_rawtxbytes(coin,txobj,msgtx); - *signedtxidp = msgtx->txid; - //printf("SIG.%d VERIFIED %s (%s)\n",vini,*signedtx,jprint(txobj,1)); - flag = 1; - break; - } - } else printf("bitcoin_verifyvins: vini.%d n2.%d\n",vini,n2); } - if ( flag > 0 ) - { - retval++; - break; - } - if ( vp->type != IGUANA_SCRIPT_76A988AC && vp->type != IGUANA_SCRIPT_76AC ) - break; - } - } - return(retval); -} - -int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,char *rawtxstr,struct vin_info *V) -{ - int32_t len,maxsize,numvins,retval = -1; uint8_t *serialized,*serialized2; - struct iguana_msgtx msgtx; bits256 txid; char vpnstr[64]; - len = (int32_t)strlen(rawtxstr); - maxsize = len + 32768; - serialized = calloc(1,maxsize), serialized2 = calloc(1,maxsize); - len >>= 1; - vpnstr[0] = 0; - decode_hex(serialized,len,rawtxstr); - memset(&msgtx,0,sizeof(msgtx)); - if ( iguana_rwmsgtx(coin,0,0,serialized,maxsize,&msgtx,&txid,vpnstr) > 0 ) - { - numvins = msgtx.tx_in; - if ( bitcoin_verifyvins(coin,signedtxidp,signedtx,&msgtx,serialized2,maxsize,V,0) == 0 ) - retval = 0; - else printf("bitcoin_verifytx: bitcoin_verifyvins error\n"); - } else printf("bitcoin_verifytx: error iguana_rwmsgtx\n"); - free(serialized), free(serialized2); - return(retval); -} - -char *bitcoin_json2hex(struct iguana_info *coin,bits256 *txidp,cJSON *txjson) -{ - int32_t txstart; uint8_t *serialized; struct iguana_msgtx msgtx; char *txbytes = 0; - serialized = malloc(IGUANA_MAXPACKETSIZE*1.5); - *txidp = iguana_parsetxobj(coin,&txstart,serialized,IGUANA_MAXPACKETSIZE*1.5,&msgtx,txjson); - if ( msgtx.allocsize > 0 ) - { - txbytes = malloc(msgtx.allocsize*2 + 1); - init_hexbytes_noT(txbytes,&serialized[txstart],msgtx.allocsize); - } else printf("bitcoin_txtest: zero msgtx allocsize.(%s)\n",jprint(txjson,0)); - free(serialized); - return(txbytes); -} - -cJSON *bitcoin_hex2json(struct iguana_info *coin,bits256 *txidp,struct iguana_msgtx *msgtx,char *txbytes) -{ - int32_t n,len; char vpnstr[64]; struct iguana_msgtx M; uint8_t *serialized; cJSON *txobj; - txobj = cJSON_CreateObject(); - if ( msgtx == 0 ) - { - msgtx = &M; - memset(msgtx,0,sizeof(M)); - } - len = (int32_t)strlen(txbytes) >> 1; - serialized = malloc(len + 32768); - decode_hex(serialized,len,txbytes); - vpnstr[0] = 0; - memset(txidp,0,sizeof(*txidp)); - printf("B bitcoin_hex2json len.%d\n",len); - if ( (n= iguana_rwmsgtx(coin,0,txobj,serialized,len + 32768,msgtx,txidp,vpnstr)) <= 0 ) - { - printf("error from rwmsgtx\n"); - free_json(txobj); - txobj = 0; - } - free(serialized); - return(txobj); -} - -cJSON *bitcoin_createtx(struct iguana_info *coin,uint32_t locktime) -{ - cJSON *json = cJSON_CreateObject(); - if ( locktime == 0 ) - { - jaddnum(json,"version",1); - jaddnum(json,"locktime",0); - } - else - { - jaddnum(json,"version",4); - jaddnum(json,"locktime",locktime); - } - if ( coin->chain->hastimestamp != 0 ) - jaddnum(json,"timestamp",time(NULL)); - jadd(json,"vin",cJSON_CreateArray()); - jadd(json,"vout",cJSON_CreateArray()); - return(json); -} - -cJSON *bitcoin_addoutput(struct iguana_info *coin,cJSON *txobj,uint8_t *paymentscript,int32_t len,uint64_t satoshis) -{ - char *hexstr; cJSON *item,*skey,*vouts = jduplicate(jobj(txobj,"vout")); - jdelete(txobj,"vout"); - item = cJSON_CreateObject(); - jaddnum(item,"value",dstr(satoshis)); - skey = cJSON_CreateObject(); - hexstr = malloc(len*2 + 1); - init_hexbytes_noT(hexstr,paymentscript,len); - jaddstr(skey,"hex",hexstr); - //printf("addoutput.(%s %s)\n",hexstr,jprint(skey,0)); - free(hexstr); - jadd(item,"scriptPubkey",skey); - jaddi(vouts,item); - jadd(txobj,"vout",vouts); - return(txobj); -} - -cJSON *bitcoin_addinput(struct iguana_info *coin,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequenceid,uint8_t *script,int32_t scriptlen,uint8_t *redeemscript,int32_t p2shlen) -{ - cJSON *item,*vins; char p2shscriptstr[IGUANA_MAXSCRIPTSIZE*2+1]; - vins = jduplicate(jobj(txobj,"vin")); - jdelete(txobj,"vin"); - item = cJSON_CreateObject(); - if ( script != 0 && scriptlen > 0 ) - iguana_addscript(coin,item,script,scriptlen,"scriptPubKey"); - if ( redeemscript != 0 && p2shlen > 0 ) - { - init_hexbytes_noT(p2shscriptstr,redeemscript,p2shlen); - jaddstr(item,"redeemScript",p2shscriptstr); + //printf("numunspents.%d -> %d total %.8f\n",*numunspentsp,n,dstr(total)); + *numunspentsp = n; + free_json(utxo); + } else printf("error parsing.(%s)\n",retstr); + if ( retstrp != 0 ) + *retstrp = retstr; + else free(retstr); } - jaddbits256(item,"txid",txid); - jaddnum(item,"vout",vout); - jaddnum(item,"sequence",sequenceid); - jaddi(vins,item); - jadd(txobj,"vin",vins); - printf("addvin -> (%s)\n",jprint(txobj,0)); - return(txobj); + *balancep = dstr(total); + return(unspents); } struct bitcoin_unspent *iguana_bestfit(struct iguana_info *coin,struct bitcoin_unspent *unspents,int32_t numunspents,uint64_t value,int32_t mode) @@ -876,277 +311,6 @@ struct bitcoin_spend *iguana_spendset(struct supernet_info *myinfo,struct iguana } } -void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON *txobj,uint32_t sequence) -{ - int32_t i; - for (i=0; inuminputs; i++) - { - spend->inputs[i].sequence = sequence; - bitcoin_addinput(coin,txobj,spend->inputs[i].txid,spend->inputs[i].vout,spend->inputs[i].sequence,spend->inputs[i].spendscript,spend->inputs[i].spendlen,spend->inputs[i].p2shscript,spend->inputs[i].p2shlen); - } -} - -cJSON *iguana_signtx(struct iguana_info *coin,bits256 *txidp,char **signedtxp,struct bitcoin_spend *spend,cJSON *txobj) -{ - int32_t i,j; char *rawtxstr; struct vin_info V; bits256 txid; - for (i=0; inuminputs; i++) // N times less efficient, but for small number of inputs ok - { - if ( *signedtxp != 0 ) - { - if ( txobj != 0 ) - free_json(txobj); - txobj = bitcoin_hex2json(coin,&txid,0,*signedtxp); - free(*signedtxp); - } - if ( (rawtxstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 ) - { - memset(&V,0,sizeof(V)); - for (j=0; jinputs[i].privkeys)/sizeof(*spend->inputs[i].privkeys); j++) - { - if ( bits256_nonz(spend->inputs[i].privkeys[j]) != 0 ) - V.signers[j].privkey = spend->inputs[i].privkeys[j]; - } - if ( spend->inputs[i].spendlen > 0 ) - { - memcpy(V.spendscript,spend->inputs[i].spendscript,spend->inputs[i].spendlen); - V.spendlen = spend->inputs[i].spendlen; - } - V.sequence = spend->inputs[i].sequence; - //printf("json2hex.(%s)\n",rawtxstr); - bitcoin_verifytx(coin,txidp,signedtxp,rawtxstr,&V); - //printf("json2hex.(%s)\n",rawtxstr); - free(rawtxstr); - } else break; - } - if ( *signedtxp != 0 && i != spend->numinputs ) - free(*signedtxp), *signedtxp = 0; - return(txobj); -} - -int32_t iguana_validatesigs(struct iguana_info *coin,struct iguana_msgvin *vin) -{ - // multiple coins - // ro -> vouts collision, purgeable - // - return(0); -} - -#ifdef testing -char *bitcoin_cltvtx(struct iguana_info *coin,char *changeaddr,char *senderaddr,char *senders_otheraddr,char *otheraddr,uint32_t locktime,uint64_t satoshis,bits256 txid,int32_t vout,uint64_t inputsatoshis,bits256 privkey) -{ - uint64_t change; char *rawtxstr,*signedtx; struct vin_info V; bits256 cltxid,signedtxid; - int32_t cltvlen,len; uint32_t timestamp; char ps2h_coinaddr[65]; cJSON *txobj; - uint8_t p2sh_rmd160[20],cltvscript[1024],paymentscript[64],rmd160[20],secret160[20],addrtype; - timestamp = (uint32_t)time(NULL); - bitcoin_addr2rmd160(&addrtype,secret160,senders_otheraddr); - cltvlen = bitcoin_cltvscript(coin->chain->p2shtype,ps2h_coinaddr,p2sh_rmd160,cltvscript,0,senderaddr,otheraddr,secret160,locktime); - txobj = bitcoin_createtx(coin,locktime); - len = bitcoin_p2shspend(paymentscript,0,p2sh_rmd160); - bitcoin_addoutput(coin,txobj,paymentscript,len,satoshis); - bitcoin_addinput(coin,txobj,txid,vout,locktime); - if ( inputsatoshis > (satoshis + 10000) ) - { - change = inputsatoshis - (satoshis + 10000); - if ( changeaddr != 0 && changeaddr[0] != 0 ) - { - bitcoin_addr2rmd160(&addrtype,rmd160,changeaddr); - if ( addrtype == coin->chain->pubtype ) - len = bitcoin_standardspend(paymentscript,0,rmd160); - else if ( addrtype == coin->chain->p2shtype ) - len = bitcoin_standardspend(paymentscript,0,rmd160); - else - { - printf("error with mismatched addrtype.%02x vs (%02x %02x)\n",addrtype,coin->chain->pubtype,coin->chain->p2shtype); - return(0); - } - bitcoin_addoutput(coin,txobj,paymentscript,len,change); - } - else - { - printf("error no change address when there is change\n"); - return(0); - } - } - rawtxstr = bitcoin_json2hex(coin,&cltxid,txobj); - char str[65]; printf("CLTV.%s (%s)\n",bits256_str(str,cltxid),rawtxstr); - memset(&V,0,sizeof(V)); - V.signers[0].privkey = privkey; - bitcoin_verifytx(coin,&signedtxid,&signedtx,rawtxstr,&V); - free(rawtxstr); - if ( signedtx != 0 ) - printf("signed CLTV.%s (%s)\n",bits256_str(str,signedtxid),signedtx); - else printf("error generating signedtx\n"); - free_json(txobj); - return(signedtx); -} -#endif - -char *refstr = "01000000\ -01\ -eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2\ -01000000\ -8c\ -4930460221009e0339f72c793a89e664a8a932df073962a3f84eda0bd9e02084a6a9567f75aa022100bd9cbaca2e5ec195751efdfac164b76250b1e21302e51ca86dd7ebd7020cdc0601410450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6\ -ffffffff\ -01\ -605af40500000000\ -19\ -76a914097072524438d003d23a2f23edb65aae1bb3e46988ac\ -00000000"; - -cJSON *bitcoin_txtest(struct iguana_info *coin,char *rawtxstr,bits256 txid) -{ - struct iguana_msgtx msgtx; char str[65],str2[65]; bits256 checktxid,blockhash,signedtxid; - cJSON *retjson,*txjson; uint8_t *serialized,*serialized2; uint32_t firstvout; - struct vin_info *V; char vpnstr[64],*txbytes,*signedtx; int32_t n,txstart,height,n2,maxsize,len; -rawtxstr = refstr; - len = (int32_t)strlen(rawtxstr); - maxsize = len + 32768; - serialized = calloc(1,maxsize); - serialized2 = calloc(1,maxsize); - len >>= 1; - V = 0; - vpnstr[0] = 0; - memset(&msgtx,0,sizeof(msgtx)); - if ( len < maxsize ) - { - decode_hex(serialized,len,rawtxstr); - txjson = cJSON_CreateObject(); - retjson = cJSON_CreateObject(); - if ( (n= iguana_rwmsgtx(coin,0,txjson,serialized,maxsize,&msgtx,&txid,vpnstr)) < 0 ) - { - printf("bitcoin_txtest len.%d: n.%d from (%s)\n",len,n,rawtxstr); - free(serialized), free(serialized2); - return(cJSON_Parse("{\"error\":\"cant parse txbytes\"}")); - } - V = calloc(msgtx.tx_in,sizeof(*V)); - { - //char *pstr; int32_t plen; - decode_hex(V[0].signers[0].privkey.bytes,sizeof(V[0].signers[0].privkey),"18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725"); - //pstr = "0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6"; - //plen = (int32_t)strlen(pstr); - //decode_hex(V[0].signers[0].pubkey,plen,pstr); - } - if ( bitcoin_verifytx(coin,&signedtxid,&signedtx,rawtxstr,V) != 0 ) - printf("bitcoin_verifytx error\n"); - jadd(retjson,"result",txjson); - if ( (firstvout= iguana_unspentindfind(coin,&height,txid,0,coin->bundlescount-1)) != 0 ) - { - if ( height >= 0 ) - { - blockhash = iguana_blockhash(coin,height); - jaddnum(retjson,"height",height); - jaddnum(retjson,"confirmations",coin->longestchain - height); - jaddbits256(retjson,"blockhash",blockhash); - } - } - //printf("retjson.(%s) %p\n",jprint(retjson,0),retjson); - memset(checktxid.bytes,0,sizeof(checktxid)); - if ( (n2= iguana_rwmsgtx(coin,1,0,serialized2,maxsize,&msgtx,&checktxid,vpnstr)) < 0 || n != n2 ) - { - printf("bitcoin_txtest: n.%d vs n2.%d\n",n,n2); - free(serialized), free(serialized2), free(V); - return(retjson); - } - if ( bits256_cmp(checktxid,txid) != 0 ) - { - printf("bitcoin_txtest: txid.%s vs check.%s\n",bits256_str(str,txid),bits256_str(str2,checktxid)); - } - checktxid = iguana_parsetxobj(coin,&txstart,serialized,maxsize,&msgtx,jobj(retjson,"result")); - if ( bits256_cmp(checktxid,txid) != 0 ) - { - printf("bitcoin_txtest: txid.%s vs check2.%s\n",bits256_str(str,txid),bits256_str(str2,checktxid)); - } - if ( msgtx.allocsize != 0 ) - { - txbytes = malloc(msgtx.allocsize*2 + 1); - init_hexbytes_noT(txbytes,&serialized[txstart],msgtx.allocsize); - if ( strcmp(txbytes,rawtxstr) != 0 ) - printf("bitcoin_txtest: reconstruction error: %s != %s\n",rawtxstr,txbytes); - else printf("reconstruction PASSED\n"); - free(txbytes); - } else printf("bitcoin_txtest: zero msgtx allocsize\n"); - free(serialized), free(serialized2), free(V); - return(retjson); - } - free(serialized), free(serialized2); - return(cJSON_Parse("{\"error\":\"testing bitcoin txbytes\"}")); -} - -uint64_t bitcoin_parseunspent(struct iguana_info *coin,struct bitcoin_unspent *unspent,double minconfirms,char *account,cJSON *item) -{ - uint8_t addrtype; char *hexstr,*wifstr,coinaddr[64],args[128]; - memset(unspent,0,sizeof(*unspent)); - if ( jstr(item,"address") != 0 ) - { - safecopy(coinaddr,jstr(item,"address"),sizeof(coinaddr)); - bitcoin_addr2rmd160(&unspent->addrtype,unspent->rmd160,coinaddr); - sprintf(args,"[\"%s\"]",coinaddr); - wifstr = bitcoind_RPC(0,coin->symbol,coin->chain->serverport,coin->chain->userpass,"dumpprivkey",args); - if ( wifstr != 0 ) - { - bitcoin_wif2priv(&addrtype,&unspent->privkeys[0],wifstr); - //printf("wifstr.(%s) -> %s\n",wifstr,bits256_str(str,unspent->privkeys[0])); - free(wifstr); - } else fprintf(stderr,"error (%s) cant find privkey\n",coinaddr); - } - if ( (account == 0 || jstr(item,"account") == 0 || strcmp(account,jstr(item,"account")) == 0) && (minconfirms <= 0 || juint(item,"confirmations") >= minconfirms-SMALLVAL) ) - { - if ( (hexstr= jstr(item,"scriptPubKey")) != 0 ) - { - unspent->spendlen = (int32_t)strlen(hexstr) >> 1; - if ( unspent->spendlen < sizeof(unspent->spendscript) ) - decode_hex(unspent->spendscript,unspent->spendlen,hexstr); - } - unspent->txid = jbits256(item,"txid"); - unspent->value = SATOSHIDEN * jdouble(item,"amount"); - unspent->vout = jint(item,"vout"); - //char str[65]; printf("(%s) -> %s %.8f scriptlen.%d\n",jprint(item,0),bits256_str(str,unspent->txid),dstr(unspent->value),unspent->scriptlen); - } else printf("skip.(%s) minconfirms.%f\n",jprint(item,0),minconfirms); - return(unspent->value); -} - -struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,char **retstrp,double *balancep,int32_t *numunspentsp,double minconfirms,char *account) -{ - char params[128],*retstr; uint64_t value,total = 0; struct bitcoin_unspent *unspents=0; cJSON *utxo; int32_t i,n; - if ( account != 0 && account[0] == 0 ) - account = 0; - *numunspentsp = 0; - if ( retstrp != 0 ) - *retstrp = 0; - sprintf(params,"%.0f, 99999999",minconfirms); - if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listunspent",params)) != 0 ) - { - //printf("sss unspents.(%s)\n",retstr); - if ( (utxo= cJSON_Parse(retstr)) != 0 ) - { - n = 0; - if ( (*numunspentsp= cJSON_GetArraySize(utxo)) > 0 ) - { - unspents = calloc(*numunspentsp,sizeof(*unspents)); - for (i=0; i<*numunspentsp; i++) - { - value = bitcoin_parseunspent(coin,&unspents[n],minconfirms,account,jitem(utxo,i)); - //printf("i.%d n.%d value %.8f\n",i,n,dstr(value)); - if ( value != 0 ) - { - total += value; - n++; - } - } - } - //printf("numunspents.%d -> %d total %.8f\n",*numunspentsp,n,dstr(total)); - *numunspentsp = n; - free_json(utxo); - } else printf("error parsing.(%s)\n",retstr); - if ( retstrp != 0 ) - *retstrp = retstr; - else free(retstr); - } - *balancep = dstr(total); - return(unspents); -} - #define EXCHANGE_NAME "bitcoin" #define UPDATE bitcoin ## _price #define SUPPORTS bitcoin ## _supports @@ -1367,69 +531,3 @@ struct exchange_funcs bitcoin_funcs = EXCHANGE_FUNCS(bitcoin,EXCHANGE_NAME); #include "exchange_undefs.h" - -#include "../../includes/iguana_apidefs.h" -#include "../../includes/iguana_apideclares.h" - -char *_setVsigner(struct iguana_info *coin,struct vin_info *V,int32_t ind,char *pubstr,char *wifstr) -{ - uint8_t addrtype; - decode_hex(V->signers[ind].pubkey,(int32_t)strlen(pubstr)/2,pubstr); - bitcoin_wif2priv(&addrtype,&V->signers[ind].privkey,wifstr); - if ( addrtype != coin->chain->pubtype ) - return(clonestr("{\"error\":\"invalid wifA\"}")); - else return(0); -} - -int32_t bitcoin_txaddspend(struct iguana_info *coin,cJSON *txobj,char *destaddress,double destamount) -{ - uint8_t outputscript[128],addrtype,rmd160[20]; int32_t scriptlen; - if ( bitcoin_validaddress(coin,destaddress) == 0 && destamount > 0. ) - { - bitcoin_addr2rmd160(&addrtype,rmd160,destaddress); - scriptlen = bitcoin_standardspend(outputscript,0,rmd160); - bitcoin_addoutput(coin,txobj,outputscript,scriptlen,destamount * SATOSHIDEN); - return(0); - } else return(-1); -} - -P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount,destaddress2,destamount2,M,N,pubA,wifA,pubB,wifB,pubC,wifC) -{ - struct vin_info V; uint8_t p2sh_rmd160[20],serialized[2096],spendscript[32]; int32_t spendlen; - char msigaddr[64],*retstr; cJSON *retjson,*txobj; struct iguana_info *active; - bits256 signedtxid; char *signedtx; - struct iguana_msgtx msgtx; - if ( (active= iguana_coinfind(activecoin)) == 0 ) - return(clonestr("{\"error\":\"activecoin isnt active\"}")); - if ( M > N || N > 3 ) - return(clonestr("{\"error\":\"illegal M or N\"}")); - memset(&V,0,sizeof(V)); - txobj = bitcoin_createtx(active,0); - if ( destaddress[0] != 0 && destamount > 0. ) - bitcoin_txaddspend(active,txobj,destaddress,destamount); - if ( destaddress2[0] != 0 && destamount2 > 0. ) - bitcoin_txaddspend(active,txobj,destaddress2,destamount2); - if ( pubA[0] != 0 && (retstr= _setVsigner(active,&V,0,pubA,wifA)) != 0 ) - return(retstr); - if ( N >= 2 && pubB[0] != 0 && (retstr= _setVsigner(active,&V,1,pubB,wifC)) != 0 ) - return(retstr); - if ( N == 3 && pubC[0] != 0 && (retstr= _setVsigner(active,&V,2,pubC,wifC)) != 0 ) - return(retstr); - V.M = M, V.N = N, V.type = IGUANA_SCRIPT_P2SH; - V.p2shlen = bitcoin_MofNspendscript(p2sh_rmd160,V.p2shscript,0,&V); - spendlen = bitcoin_p2shspend(spendscript,0,p2sh_rmd160); - bitcoin_addinput(active,txobj,vintxid,vinvout,0xffffffff,spendscript,spendlen,V.p2shscript,V.p2shlen); - bitcoin_address(msigaddr,active->chain->p2shtype,V.p2shscript,V.p2shlen); - retjson = cJSON_CreateObject(); - if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,&msgtx,serialized,sizeof(serialized),&V,0) == 0 ) - { - jaddstr(retjson,"result","msigtx"); - if ( signedtx != 0 ) - jaddstr(retjson,"signedtx",signedtx), free(signedtx); - jaddbits256(retjson,"txid",signedtxid); - } else jaddstr(retjson,"error","couldnt sign tx"); - jaddstr(retjson,"msigaddr",msigaddr); - return(jprint(retjson,1)); -} -#include "../../includes/iguana_apiundefs.h" - diff --git a/iguana/iguana.sources b/iguana/iguana.sources index da7362e5e..f0c09fc49 100755 --- a/iguana/iguana.sources +++ b/iguana/iguana.sources @@ -1,5 +1,2 @@ -#iguana_html.c -#SOURCES := iguana_rpc.c SuperNET.c SuperNET_keys.c SuperNET_category.c SuperNET_hexmsg.c iguana_exchanges.c iguana_tradebots.c iguana_instantdex.c pangea_api.c pangea_bets.c cards777.c pangea_summary.c pangea_json.c pangea_hand.c poker.c ramchain_api.c iguana_tx.c iguana_wallet.c iguana_scripts.c iguana_pubkeys.c iguana_unspents.c iguana_recv.c iguana_bundles.c iguana_msg.c iguana777.c iguana_chains.c iguana_peers.c iguana_accept.c iguana_bitmap.c iguana_init.c iguana_ramchain.c iguana_blocks.c iguana_json.c main.c peggy.c peggy_consensus.c peggy_price.c peggy_update.c peggy_accts.c peggy_tx.c peggy_txind.c peggy_ramkv.c peggy_serdes.c - -SOURCES := SuperNET.c iguana_bundles.c main.c peggy_price.c SuperNET_category.c iguana_chains.c iguana_ramchain.c pangea_api.c peggy_ramkv.c SuperNET_hexmsg.c iguana_exchanges.c iguana_recv.c pangea_bets.c peggy_serdes.c SuperNET_keys.c iguana_html.c iguana_rpc.c pangea_hand.c peggy_tx.c cards777.c iguana_init.c iguana_scripts.c pangea_json.c peggy_txind.c iguana777.c iguana_instantdex.c iguana_tradebots.c pangea_summary.c peggy_update.c iguana_accept.c iguana_json.c iguana_tx.c peggy.c poker.c iguana_bitmap.c iguana_msg.c iguana_unspents.c peggy_accts.c ramchain_api.c iguana_blocks.c iguana_peers.c iguana_wallet.c peggy_consensus.c databases/iguana_DB.c \ No newline at end of file +SOURCES := SuperNET.c iguana_bundles.c main.c igana_payment.c iguana_spendvectors.c iguana_sign.c iguana_txidfind.c iguana_realtime.c iguana_volatiles.c peggy_price.c SuperNET_category.c iguana_chains.c iguana_ramchain.c pangea_api.c peggy_ramkv.c SuperNET_hexmsg.c iguana_exchanges.c iguana_recv.c pangea_bets.c peggy_serdes.c SuperNET_keys.c iguana_rpc.c pangea_hand.c peggy_tx.c cards777.c iguana_init.c iguana_scripts.c pangea_json.c peggy_txind.c iguana777.c iguana_instantdex.c iguana_tradebots.c pangea_summary.c peggy_update.c iguana_accept.c iguana_json.c iguana_tx.c peggy.c poker.c iguana_bitmap.c iguana_msg.c iguana_unspents.c peggy_accts.c ramchain_api.c iguana_blocks.c iguana_peers.c iguana_wallet.c peggy_consensus.c databases/iguana_DB.c \ No newline at end of file diff --git a/iguana/iguana777.h b/iguana/iguana777.h index f42fd89d3..c61f15fb3 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -474,7 +474,7 @@ struct iguana_bundlereq struct iguana_bitmap { int32_t width,height,amplitude; char name[52]; uint8_t data[IGUANA_WIDTH*IGUANA_HEIGHT*3]; }; -struct iguana_waddress { UT_hash_handle hh; uint16_t scriptlen; uint8_t rmd160[20],type,pubkey[33],wiftype; bits256 privkey; char symbol[8],coinaddr[36],wifstr[54]; uint8_t redeemScript[]; }; +struct iguana_waddress { UT_hash_handle hh; uint64_t balance,*unspents; uint32_t maxunspents,numunspents; uint16_t scriptlen; uint8_t rmd160[20],pubkey[33],wiftype,addrtype; bits256 privkey; char symbol[8],coinaddr[36],wifstr[54]; uint8_t redeemScript[]; }; struct iguana_waccount { UT_hash_handle hh; char account[128]; struct iguana_waddress *waddr,*current; }; struct iguana_wallet { UT_hash_handle hh; struct iguana_waccount *wacct; }; @@ -531,7 +531,7 @@ struct vin_info struct bitcoin_unspent { bits256 txid,privkeys[16]; uint64_t value; int32_t vout,spendlen,p2shlen; uint32_t sequence; - uint8_t addrtype,rmd160[20],pubkey[65],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE]; + uint8_t addrtype,rmd160[20],pubkeys[16][65],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE]; }; struct bitcoin_spend @@ -827,11 +827,10 @@ int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr char *issue_startForging(struct supernet_info *myinfo,char *secret); struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,char **retstrp,double *balancep,int32_t *numunspentsp,double minconfirms,char *account); void iguana_chainparms(struct iguana_chain *chain,cJSON *argjson); -void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON *txobj,uint32_t sequence); -int32_t iguana_pkhasharray(struct supernet_info *myinfo,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 lastheight); +int32_t iguana_pkhasharray(struct supernet_info *myinfo,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 lastheight,uint64_t *unspents,int32_t *numunspentsp); long iguana_spentsfile(struct iguana_info *coin,int32_t n); uint8_t *iguana_rmdarray(struct iguana_info *coin,int32_t *numrmdsp,cJSON *array,int32_t firsti); -int64_t iguana_unspents(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,uint8_t *rmdarray,int32_t numrmds,int32_t lastheight); +int64_t iguana_unspents(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,uint8_t *rmdarray,int32_t numrmds,int32_t lastheight,uint64_t *unspents,int32_t *numunspentsp); uint8_t *iguana_walletrmds(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *numrmdsp); char *iguana_bundleaddrs(struct iguana_info *coin,int32_t hdrsi); uint32_t iguana_sparseaddpk(uint8_t *bits,int32_t width,uint32_t tablesize,uint8_t rmd160[20],struct iguana_pkhash *P,uint32_t pkind,struct iguana_ramchain *ramchain); @@ -928,6 +927,16 @@ int64_t iguana_addressreceived(struct supernet_info *myinfo,struct iguana_info * cJSON *iguana_walletjson(struct supernet_info *myinfo); int32_t iguana_payloadupdate(struct supernet_info *myinfo,struct iguana_info *coin,char *retstr,struct iguana_waddress *waddr,char *account); int32_t bitcoin_MofNspendscript(uint8_t p2sh_rmd160[20],uint8_t *script,int32_t n,const struct vin_info *vp); +cJSON *iguana_p2shjson(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *retjson,struct iguana_waddress *waddr); +char *setaccount(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waddress **waddrp,char *account,char *coinaddr,char *redeemScript); +char *iguana_APIrequest(struct iguana_info *coin,bits256 blockhash,bits256 txid,int32_t seconds); +int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighashsingle); +int64_t iguana_fastfindcreate(struct iguana_info *coin); +int32_t bitcoin_validaddress(struct iguana_info *coin,char *coinaddr); +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); +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); +int32_t iguana_unspentslists(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waddress **waddrs,int32_t maxwaddrs,int64_t required,int32_t minconf,char *account); +int64_t iguana_unspentset(struct supernet_info *myinfo,struct iguana_info *coin); extern int32_t HDRnet,netBLOCKS; diff --git a/iguana/iguana_bundles.c b/iguana/iguana_bundles.c index 6f3a324e0..a183e08df 100755 --- a/iguana/iguana_bundles.c +++ b/iguana/iguana_bundles.c @@ -416,6 +416,35 @@ struct iguana_txid *iguana_bundletx(struct iguana_info *coin,struct iguana_bundl return(0); } +char *iguana_bundleaddrs(struct iguana_info *coin,int32_t hdrsi) +{ + uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind,numpkinds; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; cJSON *retjson; char rmdstr[41]; + if ( (bp= coin->bundles[hdrsi]) != 0 ) + { + if ( 0 && coin->RTramchain_busy != 0 ) + { + printf("iguana_bundleaddrs: unexpected access when RTramchain_busy\n"); + return(0); + } + ramchain = &bp->ramchain;//(bp->isRT != 0) ? &bp->ramchain : &coin->RTramchain; + if ( ramchain->H.data != 0 ) + { + numpkinds = ramchain->H.data->numpkinds;//(bp->isRT != 0) ? ramchain->H.data->numpkinds : ramchain->pkind; + 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; pkindrmd160,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\"}")); +} + void iguana_bundlepurgefiles(struct iguana_info *coin,struct iguana_bundle *bp) { static const bits256 zero; diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c new file mode 100755 index 000000000..447d358ea --- /dev/null +++ b/iguana/iguana_payments.c @@ -0,0 +1,672 @@ +/****************************************************************************** + * 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" + +char *iguana_APIrequest(struct iguana_info *coin,bits256 blockhash,bits256 txid,int32_t seconds) +{ + int32_t i,len; char *retstr = 0; uint8_t serialized[1024]; char str[65]; + coin->APIblockhash = blockhash; + coin->APItxid = txid; + printf("request block.(%s) txid.%llx\n",bits256_str(str,blockhash),(long long)txid.txid); + if ( (len= iguana_getdata(coin,serialized,MSG_BLOCK,&blockhash,1)) > 0 ) + { + for (i=0; iAPIblockstr != 0 ) + { + retstr = coin->APIblockstr; + coin->APIblockstr = 0; + memset(&coin->APIblockhash,0,sizeof(coin->APIblockhash)); + memset(&coin->APItxid,0,sizeof(coin->APItxid)); + return(retstr); + } + sleep(1); + } + } + return(0); +} + +bits256 iguana_str2priv(struct supernet_info *myinfo,struct iguana_info *coin,char *str) +{ + bits256 privkey; int32_t n; uint8_t addrtype; struct iguana_waccount *wacct=0; struct iguana_waddress *waddr; + memset(&privkey,0,sizeof(privkey)); + if ( str != 0 ) + { + n = (int32_t)strlen(str) >> 1; + if ( n == sizeof(bits256) && is_hexstr(str,sizeof(bits256)) > 0 ) + decode_hex(privkey.bytes,sizeof(privkey),str); + else if ( bitcoin_wif2priv(&addrtype,&privkey,str) != sizeof(bits256) ) + { + if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,str)) != 0 ) + privkey = waddr->privkey; + else memset(privkey.bytes,0,sizeof(privkey)); + } + } + return(privkey); +} + +int32_t iguana_pubkeyget(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *pubkey33,char *str) +{ + bits256 privkey,pubkey; uint8_t pubkeydata[128]; int32_t len,plen= -1; struct iguana_waccount *wacct; struct iguana_waddress *waddr; + len = (int32_t)strlen(str); + if ( is_hexstr(str,len) == 0 ) + { + if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,str)) != 0 ) + { + if ( (plen= bitcoin_pubkeylen(waddr->pubkey)) > 0 ) + memcpy(pubkeydata,waddr->pubkey,plen); + } + } + else + { + decode_hex(pubkeydata,len,str); + plen = bitcoin_pubkeylen(pubkeydata); + } + if ( plen <= 0 ) + { + privkey = iguana_str2priv(myinfo,coin,str); + if ( bits256_nonz(privkey) == 0 ) + return(-1); + else + { + pubkey = bitcoin_pubkey33(pubkeydata,privkey); + if ( bits256_nonz(pubkey) == 0 ) + return(-1); + } + } + if ( (plen= bitcoin_pubkeylen(pubkeydata)) > 0 ) + memcpy(pubkey33,pubkeydata,plen); + return(0); +} + +cJSON *iguana_p2shjson(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *retjson,struct iguana_waddress *waddr) +{ + char str[4096]; uint8_t type; struct iguana_waccount *wacct; bits256 debugtxid; struct vin_info V; cJSON *privkeys,*pubkeys,*addresses; int32_t i,plen; + if ( retjson == 0 ) + retjson = cJSON_CreateObject(); + init_hexbytes_noT(str,waddr->redeemScript,waddr->scriptlen); + jaddstr(retjson,"redeemScript",str); + memset(debugtxid.bytes,0,sizeof(debugtxid)); + if ( (type= iguana_calcrmd160(coin,0,&V,waddr->redeemScript,waddr->scriptlen, debugtxid,-1,0xffffffff)) >= 0 ) + { + privkeys = cJSON_CreateArray(); + pubkeys = cJSON_CreateArray(); + addresses = cJSON_CreateArray(); + for (i=0; iwifstr[0] != 0 ) + jaddistr(privkeys,waddr->wifstr); + else jaddistr(privkeys,""); + if ( (plen= bitcoin_pubkeylen(V.signers[i].pubkey)) > 0 ) + { + init_hexbytes_noT(str,V.signers[i].pubkey,plen); + jaddistr(pubkeys,str); + } else jaddistr(pubkeys,""); + jaddistr(addresses,V.signers[i].coinaddr); + } + jaddstr(retjson,"result",V.coinaddr); + jaddnum(retjson,"M",V.M); + jaddnum(retjson,"N",V.N); + jadd(retjson,"pubkeys",pubkeys); + jadd(retjson,"privkeys",privkeys); + jadd(retjson,"addresses",addresses); + } + return(retjson); +} + +cJSON *iguana_scriptobj(struct iguana_info *coin,uint8_t rmd160[20],char *coinaddr,char *asmstr,uint8_t *script,int32_t scriptlen) +{ + struct vin_info V; int32_t i,plen,asmtype; char pubkeystr[130],rmdstr[41]; cJSON *addrobj,*scriptobj=0; + if ( (asmtype= iguana_calcrmd160(coin,asmstr,&V,script,scriptlen,rand256(1),1,0xffffffff)) >= 0 ) + { + if ( asmstr != 0 && asmstr[0] != 0 ) + jaddstr(scriptobj,"asm",asmstr); + jaddnum(scriptobj,"iguanatype",asmtype); + jaddnum(scriptobj,"scriptlen",scriptlen); + jaddnum(scriptobj,"reqSigs",V.M); + if ( (plen= bitcoin_pubkeylen(V.signers[0].pubkey)) > 0 ) + { + init_hexbytes_noT(pubkeystr,V.signers[0].pubkey,plen); + jaddstr(scriptobj,"pubkey",pubkeystr); + init_hexbytes_noT(rmdstr,V.signers[0].rmd160,20); + jaddstr(scriptobj,"rmd160",rmdstr); + } + addrobj = cJSON_CreateArray(); + for (i=0; i [comment] [comment-to] is a real and is rounded to 8 decimal places. Returns the transaction ID if successful. Y + if ( coinaddr != 0 && coinaddr[0] != 0 && amount > 0. ) + { + if ( iguana_addressvalidate(coin,&addrtype,rmd160,coinaddr) < 0 ) + return(clonestr("{\"error\":\"invalid coin address\"}")); + numwaddrs = iguana_unspentslists(myinfo,coin,(struct iguana_waddress **)coin->blockspace,(int32_t)(sizeof(coin->blockspace)/sizeof(*waddrs)),amount,minconf,0); + + printf("need to generate send %.8f to %s [%s] [%s] using numaddrs.%d\n",dstr(amount),coinaddr,comment!=0?comment:"",comment2!=0?comment2:"",numwaddrs); + } + return(clonestr("{\"error\":\"need address and amount\"}")); +} + +#include "../includes/iguana_apidefs.h" +#include "../includes/iguana_apideclares.h" + +STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees) +{ + cJSON *retjson = cJSON_CreateObject(); + // send to 2 peers + return(jprint(retjson,1)); +} + +STRING_ARG(bitcoinrpc,submitblock,rawbytes) +{ + cJSON *retjson = cJSON_CreateObject(); + // send to all peers + return(jprint(retjson,1)); +} + +ZERO_ARGS(bitcoinrpc,makekeypair) +{ + bits256 privkey; char str[67]; cJSON *retjson = cJSON_CreateObject(); + privkey = rand256(1); + jaddstr(retjson,"result","success"); + jaddstr(retjson,"privkey",bits256_str(str,privkey)); + jadd(retjson,"rosetta",SuperNET_rosettajson(privkey,1)); + return(jprint(retjson,1)); +} + +STRING_ARG(bitcoinrpc,validatepubkey,pubkeystr) +{ + uint8_t rmd160[20],pubkey[65],addrtype = 0; int32_t plen; char coinaddr[128],*str; cJSON *retjson; + plen = (int32_t)strlen(pubkeystr) >> 1; + if ( plen <= 65 && coin != 0 && coin->chain != 0 ) + { + addrtype = coin->chain->pubtype; + decode_hex(pubkey,plen,pubkeystr); + if ( (str= bitcoin_address(coinaddr,addrtype,pubkey,plen)) != 0 ) + { + if ( iguana_addressvalidate(coin,&addrtype,rmd160,coinaddr) < 0 ) + return(clonestr("{\"error\":\"invalid coin address\"}")); + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + jaddstr(retjson,"pubkey",pubkeystr); + jaddstr(retjson,"address",coinaddr); + jaddstr(retjson,"coin",coin->symbol); + return(jprint(retjson,1)); + } + } + return(clonestr("{\"error\":\"invalid pubkey\"}")); +} + +STRING_ARG(bitcoinrpc,decodescript,scriptstr) +{ + int32_t scriptlen; uint8_t script[IGUANA_MAXSCRIPTSIZE],rmd160[20]; char coinaddr[128],asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; cJSON *scriptobj,*retjson = cJSON_CreateObject(); + if ( coin != 0 && (scriptlen= (int32_t)strlen(scriptstr)>>1) < sizeof(script) ) + { + decode_hex(script,scriptlen,scriptstr); + if ( (scriptobj= iguana_scriptobj(coin,rmd160,coinaddr,asmstr,script,scriptlen)) != 0 ) + jadd(retjson,"result",scriptobj); + } + return(jprint(retjson,1)); +} + +INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,pubkeys,ignore) +{ + cJSON *retjson,*pkjson,*addresses; uint8_t script[2048],p2sh_rmd160[20]; char pubkeystr[256],msigaddr[64],*pkstr,scriptstr[sizeof(script)*2+1]; struct vin_info V; int32_t i,plen,len,n = cJSON_GetArraySize(pubkeys); + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( n < 0 || n > 16 || M < 0 || M > n ) + return(clonestr("{\"error\":\"illegal number of pubkeys\"}")); + memset(&V,0,sizeof(V)); + V.M = M, V.N = n; + pkjson = cJSON_CreateArray(); + addresses = cJSON_CreateArray(); + for (i=0; ichain->pubtype,V.signers[i].pubkey,plen); + jaddistr(addresses,V.signers[i].coinaddr); + init_hexbytes_noT(pubkeystr,V.signers[i].pubkey,plen); + jaddistr(pkjson,pubkeystr); + } else break; + } + retjson = cJSON_CreateObject(); + if ( i == n ) + { + len = bitcoin_MofNspendscript(p2sh_rmd160,script,0,&V); + bitcoin_address(msigaddr,coin->chain->p2shtype,p2sh_rmd160,sizeof(p2sh_rmd160)); + jaddstr(retjson,"result","success"); + jaddstr(retjson,"address",msigaddr); + init_hexbytes_noT(scriptstr,script,len); + jaddstr(retjson,"redeemScript",scriptstr); + jaddnum(retjson,"M",M); + jaddnum(retjson,"N",n); + jadd(retjson,"pubkeys",pkjson); + jadd(retjson,"addresses",addresses); + } + else + { + jaddstr(retjson,"error","couldnt get all pubkeys"); + free_json(pkjson); + } + return(jprint(retjson,1)); +} + +INT_ARRAY_STRING(bitcoinrpc,addmultisigaddress,M,pubkeys,account) // +{ + cJSON *retjson,*tmpjson,*setjson=0; char *retstr,*str=0,*msigaddr,*redeemScript; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + if ( (retstr= bitcoinrpc_createmultisig(IGUANA_CALLARGS,M,pubkeys,account)) != 0 ) + { + //printf("CREATEMULTISIG.(%s)\n",retstr); + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (msigaddr= jstr(retjson,"address")) != 0 ) + { + if ( (redeemScript= jstr(retjson,"redeemScript")) == 0 || (str= setaccount(myinfo,coin,0,account,msigaddr,redeemScript)) == 0 || (setjson= cJSON_Parse(str)) == 0 || jobj(setjson,"error") != 0 ) + { + if ( jobj(retjson,"result") != 0 ) + jdelete(retjson,"result"); + if ( jobj(retjson,"error") == 0 ) + jaddstr(retjson,"error","couldnt add multisig address to account"); + } + else + { + tmpjson = cJSON_CreateObject(); + jaddstr(tmpjson,"result",msigaddr); + free_json(retjson); + free(retstr); + retjson = tmpjson; + } + } + if ( setjson != 0 ) + free_json(setjson); + if ( str != 0 ) + free(str); + return(jprint(retjson,1)); + } else return(clonestr("{\"error\":\"couldnt parse retstr from createmultisig\"}")); + } else return(clonestr("{\"error\":\"no retstr from createmultisig\"}")); +} + +HASH_AND_TWOINTS(bitcoinrpc,gettxout,txid,vout,mempool) +{ + uint8_t script[IGUANA_MAXSCRIPTSIZE],rmd160[20],pubkey33[33]; char coinaddr[128],asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; struct iguana_bundle *bp; int32_t minconf,scriptlen,unspentind,height,spentheight; int64_t RTspend; struct iguana_ramchaindata *rdata; struct iguana_pkhash *P; struct iguana_txid *T; struct iguana_unspent *U; struct iguana_ramchain *ramchain; cJSON *scriptobj,*retjson = cJSON_CreateObject(); + if ( coin != 0 ) + { + minconf = (mempool != 0) ? 0 : 1; + if ( (unspentind= iguana_unspentindfind(coin,&height,txid,vout,coin->bundlescount-1)) != 0 ) + { + if ( height >= 0 && height < coin->longestchain && (bp= coin->bundles[height / coin->chain->bundlesize]) != 0 ) + { + ramchain = (bp == coin->current) ? &coin->RTramchain : &bp->ramchain; + if ( (rdata= ramchain->H.data) != 0 ) + { + U = (void *)(long)((long)rdata + rdata->Uoffset); + P = (void *)(long)((long)rdata + rdata->Poffset); + T = (void *)(long)((long)rdata + rdata->Toffset); + RTspend = 0; + if ( iguana_spentflag(coin,&RTspend,&spentheight,ramchain,bp->hdrsi,unspentind,height,minconf,coin->longestchain,U[unspentind].value) == 0 ) + { + jaddbits256(retjson,"bestblock",coin->blocks.hwmchain.RO.hash2); + jaddnum(retjson,"bestheight",coin->blocks.hwmchain.height); + jaddnum(retjson,"height",height); + jaddnum(retjson,"confirmations",coin->blocks.hwmchain.height - height + 1); + jaddnum(retjson,"value",dstr(U[unspentind].value)); + memset(rmd160,0,sizeof(rmd160)); + memset(pubkey33,0,sizeof(pubkey33)); + memset(coinaddr,0,sizeof(coinaddr)); + if ( (scriptlen= iguana_voutscript(coin,bp,script,0,&U[unspentind],&P[U[unspentind].pkind],vout)) > 0 ) + { + if ( (scriptobj= iguana_scriptobj(coin,rmd160,coinaddr,asmstr,script,scriptlen)) != 0 ) + jadd(retjson,"scriptPubKey",scriptobj); + } + jadd(retjson,"iguana",iguana_unspentjson(myinfo,coin,bp->hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33)); + if ( (height % coin->chain->bundlesize) == 0 && vout == 0 ) + jadd(retjson,"coinbase",jtrue()); + else jadd(retjson,"coinbase",jfalse()); + } + else + { + jaddstr(retjson,"error","already spent"); + jaddnum(retjson,"spentheight",spentheight); + jaddnum(retjson,"unspentind",unspentind); + } + } + } + } + } + return(jprint(retjson,1)); +} + +TWO_STRINGS(bitcoinrpc,signmessage,address,messagestr) +{ + bits256 privkey; int32_t n,len,siglen; char sigstr[256],sig64str[256]; uint8_t sig[128],*message=0; cJSON *retjson = cJSON_CreateObject(); + if ( coin != 0 ) + { + privkey = iguana_str2priv(myinfo,coin,address); + if ( bits256_nonz(privkey) != 0 ) + { + n = (int32_t)strlen(messagestr) >> 1; + if ( messagestr[0] == '0' && messagestr[1] == 'x' && is_hexstr(messagestr+2,n-2) > 0 ) + { + message = malloc(n-2); + decode_hex(message,n-2,messagestr+2); + n -= 2; + } else message = (uint8_t *)messagestr, n <<= 1; + if ( (siglen= bitcoin_sign(sig,sizeof(sig),message,n,privkey)) > 0 ) + { + sigstr[0] = sig64str[0] = 0; + //init_hexbytes_noT(sigstr,sig,siglen); + len = nn_base64_encode(sig,siglen,sig64str,sizeof(sig64str)); + sig64str[len++] = '='; + sig64str[len++] = 0; + jaddstr(retjson,"result",sig64str); + } + if ( message != (void *)messagestr ) + free(message); + } else jaddstr(retjson,"error","invalid address (can be wif, wallet address or privkey hex)"); + } + return(jprint(retjson,1)); +} + +THREE_STRINGS(bitcoinrpc,verifymessage,address,sig,message) +{ + cJSON *retjson = cJSON_CreateObject(); + return(jprint(retjson,1)); +} + +HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose) +{ + struct iguana_txid *tx,T; char *txbytes; bits256 checktxid; int32_t len,height; cJSON *retjson; + if ( (tx= iguana_txidfind(coin,&height,&T,txid,coin->bundlescount-1)) != 0 ) + { + retjson = cJSON_CreateObject(); + if ( (len= iguana_ramtxbytes(coin,coin->blockspace,sizeof(coin->blockspace),&checktxid,tx,height,0,0,0)) > 0 ) + { + txbytes = calloc(1,len*2+1); + init_hexbytes_noT(txbytes,coin->blockspace,len); + jaddstr(retjson,"result",txbytes); + printf("txbytes.(%s) len.%d (%s)\n",txbytes,len,jprint(retjson,0)); + free(txbytes); + return(jprint(retjson,1)); + } + else if ( height >= 0 ) + { + if ( coin->APIblockstr != 0 ) + jaddstr(retjson,"error","already have pending request"); + else + { + int32_t datalen; uint8_t *data; char *blockstr; bits256 blockhash; + blockhash = iguana_blockhash(coin,height); + if ( (blockstr= iguana_APIrequest(coin,blockhash,txid,2)) != 0 ) + { + datalen = (int32_t)(strlen(blockstr) >> 1); + data = malloc(datalen); + decode_hex(data,datalen,blockstr); + if ( (txbytes= iguana_txscan(coin,verbose != 0 ? retjson : 0,data,datalen,txid)) != 0 ) + { + jaddstr(retjson,"result",txbytes); + jaddbits256(retjson,"blockhash",blockhash); + jaddnum(retjson,"height",height); + free(txbytes); + } else jaddstr(retjson,"error","cant find txid in block"); + free(blockstr); + free(data); + } else jaddstr(retjson,"error","cant find blockhash"); + return(jprint(retjson,1)); + } + } else printf("height.%d\n",height); + } + return(clonestr("{\"error\":\"cant find txid\"}")); +} + +STRING_ARG(bitcoinrpc,decoderawtransaction,rawtx) +{ + cJSON *txobj = 0; bits256 txid; + if ( rawtx != 0 && rawtx[0] != 0 ) + { + if ( (strlen(rawtx) & 1) != 0 ) + return(clonestr("{\"error\":\"rawtx hex has odd length\"}")); + txobj = bitcoin_hex2json(coin,&txid,0,rawtx); + //char str[65]; printf("got txid.(%s)\n",bits256_str(str,txid)); + } + if ( txobj == 0 ) + txobj = cJSON_CreateObject(); + return(jprint(txobj,1)); +} + +HASH_ARG(bitcoinrpc,gettransaction,txid) +{ + return(bitcoinrpc_getrawtransaction(IGUANA_CALLARGS,txid,1)); +} + +ARRAY_OBJ_INT(bitcoinrpc,createrawtransaction,vins,vouts,locktime) +{ + bits256 txid; int32_t vout,offset,spendlen=0,p2shlen=0,i,n; uint32_t sequenceid; uint8_t addrtype,rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],redeemscript[IGUANA_MAXSCRIPTSIZE]; uint64_t satoshis; char *hexstr,*str,*field,*txstr; cJSON *txobj,*item,*obj,*retjson = cJSON_CreateObject(); + if ( coin != 0 && (txobj= bitcoin_createtx(coin,locktime)) != 0 ) + { + if ( (n= cJSON_GetArraySize(vins)) > 0 ) + { + for (i=0; i> 1; + decode_hex(spendscript,spendlen,str); + } + if ( (str= jstr(item,"redeemScript")) != 0 ) + { + p2shlen = (int32_t)strlen(str) >> 1; + decode_hex(redeemscript,p2shlen,str); + } + vout = jint(item,"vout"); + if ( jobj(item,"sequenceid") != 0 ) + sequenceid = juint(item,"sequenceid"); + else sequenceid = 0xffffffff; + txid = jbits256(item,"txid"); + bitcoin_addinput(coin,txobj,txid,vout,sequenceid,spendscript,spendlen,redeemscript,p2shlen); + } + } + if ( (n= cJSON_GetArraySize(vouts)) > 0 ) + { + item = vouts->child; + while ( item != 0 ) + { + if ( (field= jfieldname(item)) != 0 ) + { + if ( strcmp(field,"data") == 0 ) + { + if ( (hexstr= jstr(item,"data")) != 0 ) + { + spendlen = (int32_t)strlen(hexstr) >> 1; + offset = 0; + if ( is_hexstr(hexstr,spendlen) > 0 ) + { + decode_hex(spendscript+4,spendlen,hexstr); + spendscript[3] = SCRIPT_OPRETURN; + spendlen++; + /* 1-75 0x01-0x4b (special) data The next opcode bytes is data to be pushed onto the stack + OP_PUSHDATA1 76 0x4c (special) data The next byte contains the number of bytes to be pushed onto the stack. + OP_PUSHDATA2 77 0x4d*/ + if ( spendlen < 76 ) + { + spendscript[2] = spendlen; + offset = 2; + spendlen++; + } + else if ( spendlen <= 0xff ) + { + spendscript[2] = spendlen; + spendscript[1] = 0x4c; + offset = 1; + spendlen += 2; + } + else if ( spendlen <= 0xffff ) + { + spendscript[2] = ((spendlen >> 8) & 0xff); + spendscript[1] = (spendlen & 0xff); + spendscript[0] = 0x4d; + offset = 0; + spendlen += 3; + } + else continue; + if ( (obj= jobj(item,"amount")) != 0 ) + satoshis = get_API_float(obj) * SATOSHIDEN; + else satoshis = 0; + bitcoin_addoutput(coin,txobj,spendscript+offset,spendlen,satoshis); + } + } + break; + } + else + { + if ( bitcoin_addr2rmd160(&addrtype,rmd160,field) == sizeof(rmd160) ) + { + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + satoshis = get_API_float(item) * SATOSHIDEN; + bitcoin_addoutput(coin,txobj,spendscript,spendlen,satoshis); + } + } + } + item = item->next; + } + } + if ( (txstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 ) + { + jaddstr(retjson,"result",txstr); + free(txstr); + } + } + return(jprint(retjson,1)); +} + +TWOINTS_AND_ARRAY(bitcoinrpc,listunspent,minconf,maxconf,array) +{ + int32_t numrmds; uint8_t *rmdarray; cJSON *retjson = cJSON_CreateArray(); + if ( minconf == 0 ) + minconf = 1; + if ( maxconf == 0 ) + maxconf = 9999999; + rmdarray = iguana_rmdarray(coin,&numrmds,array,0); + iguana_unspents(myinfo,coin,retjson,minconf,maxconf,rmdarray,numrmds,0,0,0); + if ( rmdarray != 0 ) + free(rmdarray); + return(jprint(retjson,1)); +} + +INT_AND_ARRAY(bitcoinrpc,lockunspent,flag,array) +{ + cJSON *retjson = cJSON_CreateObject(); + return(jprint(retjson,1)); +} + +ZERO_ARGS(bitcoinrpc,listlockunspent) +{ + cJSON *retjson = cJSON_CreateObject(); + return(jprint(retjson,1)); +} + +DOUBLE_ARG(bitcoinrpc,settxfee,amount) +{ + cJSON *retjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + coin->txfee_perkb = amount * SATOSHIDEN; + retjson = cJSON_CreateObject(); + jadd(retjson,"result",jtrue()); + return(jprint(retjson,1)); +} + +S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2) +{ + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + iguana_unspentset(myinfo,coin); + return(sendtoaddress(myinfo,coin,address,amount,comment,comment2,coin->minconfirms,0)); +} + +SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2) +{ + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + iguana_unspentset(myinfo,coin); + return(sendtoaddress(myinfo,coin,toaddress,amount,comment,comment2,minconf,fromaccount)); +} + +S_A_I_S(bitcoinrpc,sendmany,fromaccount,payments,minconf,comment) +{ + cJSON *retjson,*item; int32_t i,n; char *coinaddr,*str; int64_t required,val; double amount; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + iguana_unspentset(myinfo,coin); + n = cJSON_GetArraySize(payments); + item = payments->child; + for (required=i=0; istring) != 0 ) + { + amount = jdouble(item,0); + val = amount * SATOSHIDEN; + printf("(%s %.8f) ",coinaddr,dstr(val)); + if ( (str= sendtoaddress(myinfo,coin,coinaddr,amount,comment,"",minconf,fromaccount)) != 0 ) + { + free(str); + } + required += val; + } + item = item->next; + } + printf("required %.8f\n",dstr(required)); + retjson = cJSON_CreateObject(); + return(jprint(retjson,1)); +} + +#include "../includes/iguana_apiundefs.h" diff --git a/iguana/iguana_realtime.c b/iguana/iguana_realtime.c new file mode 100755 index 000000000..29258c3ae --- /dev/null +++ b/iguana/iguana_realtime.c @@ -0,0 +1,355 @@ +/****************************************************************************** + * 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" + +void iguana_RTramchainfree(struct iguana_info *coin,struct iguana_bundle *bp) +{ + int32_t hdrsi; + if ( coin->utxotable != 0 ) + { + printf("free RTramchain\n"); + iguana_utxoupdate(coin,-1,0,0,0,0,-1); // free hashtables + coin->RTheight = coin->balanceswritten * coin->chain->bundlesize; + coin->RTgenesis = 0; + iguana_ramchain_free(coin,&coin->RTramchain,1); + if ( bp != 0 ) + bp->ramchain = coin->RTramchain; + iguana_mempurge(&coin->RTmem); + iguana_mempurge(&coin->RThashmem); + coin->RTdatabad = 0; + for (hdrsi=coin->bundlescount-1; hdrsi>0; hdrsi--) + if ( (bp= coin->bundles[hdrsi]) == 0 && bp != coin->current ) + { + iguana_volatilespurge(coin,&bp->ramchain); + if ( iguana_volatilesmap(coin,&bp->ramchain) != 0 ) + printf("error mapping bundle.[%d]\n",hdrsi); + } + printf("done RTramchain\n"); + } +} + +void *iguana_ramchainfile(struct iguana_info *coin,struct iguana_ramchain *dest,struct iguana_ramchain *R,struct iguana_bundle *bp,int32_t bundlei,struct iguana_block *block) +{ + char fname[1024]; long filesize; int32_t err; void *ptr=0; + if ( block == bp->blocks[bundlei] && (ptr= iguana_bundlefile(coin,fname,&filesize,bp,bundlei)) != 0 ) + { + if ( iguana_mapchaininit(fname,coin,R,bp,bundlei,block,ptr,filesize) >= 0 ) + { + if ( dest != 0 && dest->H.data != 0 ) + err = iguana_ramchain_iterate(coin,dest,R,bp,bundlei); + else err = 0; + if ( err != 0 || dest->H.data == 0 || bits256_cmp(R->H.data->firsthash2,block->RO.hash2) != 0 ) + { + char str[65]; + printf("ERROR [%d:%d] %s vs ",bp->hdrsi,bundlei,bits256_str(str,block->RO.hash2)); + printf("mapped.%s\n",bits256_str(str,R->H.data->firsthash2)); + } else return(ptr); + } + iguana_blockunmark(coin,block,bp,bundlei,1); + iguana_ramchain_free(coin,R,1); + } //else printf("ramchainfile ptr.%p block.%p\n",ptr,block); + return(0); +} + +void iguana_RTramchainalloc(char *fname,struct iguana_info *coin,struct iguana_bundle *bp) +{ + uint32_t i,changed = 0; struct iguana_ramchaindata *rdata; struct iguana_ramchain *dest = &coin->RTramchain; struct iguana_blockRO *B; struct iguana_bundle *tmpbp; + if ( (rdata= dest->H.data) != 0 ) + { + i = 0; + if ( coin->RTheight != bp->bundleheight + rdata->numblocks ) + changed++; + else + { + B = (void *)(long)((long)rdata + rdata->Boffset); + for (i=0; inumblocks; i++) + if ( bits256_cmp(B[i].hash2,bp->hashes[i]) != 0 ) + { + char str[65],str2[65]; printf("mismatched hash2 at %d %s vs %s\n",bp->bundleheight+i,bits256_str(str,B[i].hash2),bits256_str(str2,bp->hashes[i])); + changed++; + break; + } + } + if ( changed != 0 ) + { + printf("RTramchain changed %d bundlei.%d | coin->RTheight %d != %d bp->bundleheight + %d coin->RTramchain.H.data->numblocks\n",coin->RTheight,i,coin->RTheight,bp->bundleheight,rdata->numblocks); + //coin->RTheight = coin->balanceswritten * coin->chain->bundlesize; + iguana_RTramchainfree(coin,bp); + } + } + if ( coin->RTramchain.H.data == 0 ) + { + printf("ALLOC RTramchain\n"); + iguana_ramchainopen(fname,coin,dest,&coin->RTmem,&coin->RThashmem,bp->bundleheight,bp->hashes[0]); + dest->H.txidind = dest->H.unspentind = dest->H.spendind = dest->pkind = dest->H.data->firsti; + dest->externalind = dest->H.stacksize = 0; + dest->H.scriptoffset = 1; + if ( 1 ) + { + for (i=0; ihdrsi; i++) + if ( (tmpbp= coin->bundles[i]) != 0 ) + { + //iguana_volatilespurge(coin,&tmpbp->ramchain); + iguana_volatilesmap(coin,&tmpbp->ramchain); + } + sleep(1); + } + } +} + +void iguana_rdataset(struct iguana_ramchain *dest,struct iguana_ramchaindata *rdest,struct iguana_ramchain *src) +{ + *dest = *src; + dest->H.data = rdest; + *rdest = *src->H.data; + rdest->numpkinds = src->pkind; + rdest->numexternaltxids = src->externalind; + rdest->numtxids = src->H.txidind; + rdest->numunspents = src->H.unspentind; + rdest->numspends = src->H.spendind; + //printf("RT set numtxids.%u numspends.%u\n",rdest->numtxids,rdest->numspends); +} + +void iguana_rdatarestore(struct iguana_ramchain *dest,struct iguana_ramchaindata *rdest,struct iguana_ramchain *src) +{ + *src = *dest; + *src->H.data = *rdest; + src->pkind = rdest->numpkinds; + src->externalind = rdest->numexternaltxids; + src->H.txidind = rdest->numtxids; + src->H.unspentind = rdest->numunspents; + src->H.spendind = rdest->numspends; + printf("RT restore numtxids.%u numspends.%u\n",rdest->numtxids,rdest->numspends); +} + +void iguana_RThdrs(struct iguana_info *coin,struct iguana_bundle *bp,int32_t numaddrs) +{ + int32_t datalen,i; uint8_t serialized[512]; char str[65]; struct iguana_peer *addr; + for (i=0; ipeers.numranked; i++) + { + queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(bits256_str(str,bp->hashes[0])),1); + if ( (addr= coin->peers.ranked[i]) != 0 && addr->usock >= 0 && addr->dead == 0 && (datalen= iguana_gethdrs(coin,serialized,coin->chain->gethdrsmsg,bits256_str(str,bp->hashes[0]))) > 0 ) + { + iguana_send(coin,addr,serialized,datalen); + addr->pendhdrs++; + } + } +} + +void iguana_RTspendvectors(struct iguana_info *coin,struct iguana_bundle *bp) +{ + int32_t iterate,lasti,num,hdrsi,orignumemit; struct iguana_ramchain R; struct iguana_ramchaindata RDATA; + if ( bp->hdrsi <= 0 ) + return; + bp->ramchain = coin->RTramchain; + iguana_rdataset(&R,&RDATA,&coin->RTramchain); + if ( (lasti= (coin->RTheight - ((coin->RTheight/bp->n)*bp->n))) >= bp->n-1 ) + lasti = bp->n - 1; + orignumemit = bp->numtmpspends; +#ifdef __APPLE__ + iterate = 0*(coin->bundlescount-1); +#else + iterate = 0; +#endif + if ( iguana_spendvectors(coin,bp,&coin->RTramchain,coin->RTstarti,lasti,0,iterate) < 0 ) + { + printf("RTutxo error -> RTramchainfree\n"); + coin->RTdatabad = 1; + return; + } + else + { + printf("RTspendvectors calculated to %d [%d]\n",coin->RTheight,bp->hdrsi); + bp->converted = 1; + for (hdrsi=num=0; hdrsihdrsi; hdrsi++) + { +#ifdef __APPLE__ + if ( coin->bundles[hdrsi]->lastprefetch == 0 ) + { + iguana_ramchain_prefetch(coin,&coin->bundles[hdrsi]->ramchain,2); + coin->bundles[hdrsi]->lastprefetch = (uint32_t)time(NULL); + } +#endif + num += iguana_convert(coin,IGUANA_NUMHELPERS,coin->bundles[hdrsi],1,orignumemit); + } + printf("RTspendvectors converted.%d to %d\n",num,coin->RTheight); + bp->converted = (uint32_t)time(NULL); + if ( iguana_balancegen(coin,1,bp,coin->RTstarti,coin->RTheight > 0 ? coin->RTheight-1 : bp->n-1,orignumemit) < 0 ) + coin->RTdatabad = 1; + else if ( coin->RTgenesis == 0 ) + printf(">>>>>> IGUANA BTC INITIALIZATION COMPLETE <<<<<<\n"); + //printf("iguana_balancegen [%d] (%d to %d)\n",bp->hdrsi,coin->RTstarti,(coin->RTheight-1)%bp->n); + coin->RTstarti = (coin->RTheight % bp->n); + } +} + +int32_t iguana_realtime_update(struct iguana_info *coin) +{ + double startmillis0; static double totalmillis0; static int32_t num0; + struct iguana_bundle *bp; struct iguana_ramchaindata *rdata; int32_t bundlei,i,n,flag=0; bits256 hash2,*ptr; struct iguana_peer *addr; + struct iguana_block *block=0; struct iguana_blockRO *B; struct iguana_ramchain *dest=0,blockR; + if ( coin->current != 0 && (coin->blocks.hwmchain.height % coin->chain->bundlesize) == coin->chain->bundlesize-1 ) + { + block = coin->current->blocks[coin->current->n - 1]; + if ( _iguana_chainlink(coin,block) <= 0 ) + { + //printf("RT edge case couldnt link\n"); + } + else printf("RT edge case.%d\n",block->height); + } + if ( coin->spendvectorsaved <= 1 ) + return(0); + for (i=0; ibundlescount-1; i++) + { + if ( (bp= coin->bundles[i]) != 0 && (i > 0 && bp->utxofinish == 0) ) + { + if ( iguana_spendvectors(coin,bp,&bp->ramchain,0,bp->n,0,0) < 0 ) + { + printf("error generating spendvectors.[%d], exiting. just restart iguana\n",i); + exit(-1); + } // else printf("generated UTXO.[%d]\n",i); + coin->spendvectorsaved = 1; + } + } + bp = coin->current; + if ( bp == 0 || iguana_validated(coin) < bp->hdrsi ) + return(0); + if ( 1 && coin->RTheight > 0 && coin->spendvectorsaved != 1 && coin->bundlescount-1 != coin->balanceswritten ) + { + printf("RT mismatch %d != %d\n",coin->bundlescount-1,coin->balanceswritten); + coin->spendvectorsaved = 0; + iguana_RTramchainfree(coin,coin->current); + return(0); + } + if ( coin->RTdatabad == 0 && bp->hdrsi == coin->longestchain/coin->chain->bundlesize && bp->hdrsi >= coin->balanceswritten && coin->RTheight >= bp->bundleheight && coin->RTheight < bp->bundleheight+bp->n && ((coin->RTheight <= coin->blocks.hwmchain.height && time(NULL) > bp->lastRT) || time(NULL) > bp->lastRT+10) ) + { + if ( (block= bp->blocks[0]) == 0 || block->txvalid == 0 || block->mainchain == 0 ) + { + if ( block != 0 ) + { + if ( _iguana_chainlink(coin,block) <= 0 ) + { + iguana_blockunmark(coin,block,bp,0,0); + bp->issued[0] = 0; + hash2 = bp->hashes[0]; + //char str[65]; printf("RT[0] [%d:%d] %s %p\n",bp->hdrsi,0,bits256_str(str,hash2),block); + addr = coin->peers.ranked[rand() % 8]; + if ( addr != 0 && addr->usock >= 0 && addr->dead == 0 ) + iguana_sendblockreqPT(coin,addr,bp,0,hash2,0); + } + } + } + //char str[65]; printf("check longest.%d RTheight.%d hwm.%d %s %p\n",coin->longestchain,coin->RTheight,coin->blocks.hwmchain.height,bits256_str(str,bp->hashes[0]),block); + if ( bits256_cmp(coin->RThash1,bp->hashes[1]) != 0 ) + coin->RThash1 = bp->hashes[1]; + bp->lastRT = (uint32_t)time(NULL); + if ( coin->RTheight < coin->longestchain && coin->peers.numranked > 0 && time(NULL) > coin->RThdrstime+10 ) + { + iguana_RThdrs(coin,bp,coin->peers.numranked); + coin->RThdrstime = bp->lastRT; + for (i=0; ipeers.numranked; i++) + { + if ( (addr= coin->peers.ranked[i]) != 0 && addr->usock >= 0 && addr->dead == 0 ) + { + //printf("%d ",addr->numRThashes); + } + } + //printf("RTheaders %s\n",coin->symbol); + } + bp->lastRT = (uint32_t)time(NULL); + iguana_RTramchainalloc("RTbundle",coin,bp); + bp->isRT = 1; + while ( (rdata= coin->RTramchain.H.data) != 0 && coin->RTheight <= coin->blocks.hwmchain.height ) + { + if ( coin->RTdatabad != 0 ) + break; + dest = &coin->RTramchain; + B = (void *)(long)((long)rdata + rdata->Boffset); + bundlei = (coin->RTheight % coin->chain->bundlesize); + if ( (block= iguana_bundleblock(coin,&hash2,bp,bundlei)) != 0 ) + iguana_bundlehashadd(coin,bp,bundlei,block); + //printf("RT.%d vs hwm.%d starti.%d bp->n %d block.%p/%p ramchain.%p\n",coin->RTheight,coin->blocks.hwmchain.height,coin->RTstarti,bp->n,block,bp->blocks[bundlei],dest->H.data); + if ( coin->RTdatabad == 0 && block != 0 && bits256_nonz(block->RO.prev_block) != 0 ) + { + iguana_blocksetcounters(coin,block,dest); + startmillis0 = OS_milliseconds(); + if ( coin->RTdatabad == 0 && iguana_ramchainfile(coin,dest,&blockR,bp,bundlei,block) == 0 ) + { + for (i=0; in; i++) + if ( GETBIT(bp->haveblock,i) == 0 ) + bp->issued[i] = 0; + if ( (n= iguana_bundleissuemissing(coin,bp,3,1.)) > 0 ) + printf("RT issued %d priority requests [%d] to unstick stuckiters.%d\n",n,bp->hdrsi,coin->stuckiters); + for (i=bundlei; in; i++) + { + block = iguana_bundleblock(coin,&hash2,bp,i); + if ( bits256_nonz(hash2) != 0 && (block == 0 || block->txvalid == 0) ) + { + uint8_t serialized[512]; int32_t len; struct iguana_peer *addr; + //char str[65]; printf("RT error [%d:%d] %s %p\n",bp->hdrsi,i,bits256_str(str,hash2),block); + addr = coin->peers.ranked[rand() % 8]; + if ( addr != 0 && addr->usock >= 0 && addr->dead == 0 && (len= iguana_getdata(coin,serialized,MSG_BLOCK,&hash2,1)) > 0 ) + iguana_send(coin,addr,serialized,len); + coin->RTgenesis = 0; + } + if ( bits256_nonz(hash2) != 0 ) + iguana_blockQ("RTerr",coin,bp,i,hash2,1); + break; + } + return(-1); + } else iguana_ramchain_free(coin,&blockR,1); + B[bundlei] = block->RO; + totalmillis0 += (OS_milliseconds() - startmillis0); + num0++; + flag++; + coin->blocks.RO[bp->bundleheight+bundlei] = block->RO; + coin->RTheight++; + printf(">>>> RT.%d hwm.%d L.%d T.%d U.%d S.%d P.%d X.%d -> size.%ld\n",coin->RTheight,coin->blocks.hwmchain.height,coin->longestchain,dest->H.txidind,dest->H.unspentind,dest->H.spendind,dest->pkind,dest->externalind,(long)dest->H.data->allocsize); + if ( coin->RTramchain.H.data != 0 ) + coin->RTramchain.H.data->numblocks = bundlei + 1; + else break; + } else break; + } + } + n = 0; + if ( coin->RTdatabad == 0 && dest != 0 && flag != 0 && coin->RTheight >= coin->longestchain ) + { + //printf("ramchainiterate.[%d] ave %.2f micros, total %.2f seconds starti.%d num.%d\n",num0,(totalmillis0*1000.)/num0,totalmillis0/1000.,coin->RTstarti,coin->RTheight%bp->n); + if ( (n= iguana_walkchain(coin,1)) == coin->RTheight-1 ) + { + //printf("RTgenesis verified\n"); + iguana_RTspendvectors(coin,bp); + coin->RTgenesis = (uint32_t)time(NULL); + } else coin->RTdatabad = 1; + } + if ( dest != 0 && flag != 0 ) + printf("<<<< flag.%d RT.%d:%d hwm.%d L.%d T.%d U.%d S.%d P.%d X.%d -> size.%ld\n",flag,coin->RTheight,n,coin->blocks.hwmchain.height,coin->longestchain,dest->H.txidind,dest->H.unspentind,dest->H.spendind,dest->pkind,dest->externalind,dest->H.data!=0?(long)dest->H.data->allocsize:-1); + if ( coin->RTdatabad != 0 ) + { + iguana_RTramchainfree(coin,bp); + //memset(bp->hashes,0,sizeof(bp->hashes)); + memset(bp->blocks,0,sizeof(bp->blocks)); + if ( 0 && bp->speculative != 0 ) + { + ptr = bp->speculative; + bp->speculative = 0; + memset(ptr,0,sizeof(*bp->speculative)*bp->n); + myfree(ptr,(bp->n+1)*sizeof(*bp->speculative)); + } + iguana_RTramchainalloc("RTbundle",coin,bp); + } + return(flag); +} diff --git a/iguana/iguana_rpc.c b/iguana/iguana_rpc.c index 1f655e7cb..3b8dad979 100755 --- a/iguana/iguana_rpc.c +++ b/iguana/iguana_rpc.c @@ -330,7 +330,7 @@ static char *getaccountaddress(RPCARGS) return(sglue1(0,CALLGLUE,"bitcoinrpc","getaccountaddress","account",params[0])); } -static char *setaccount(RPCARGS) +static char *setaccountrpc(RPCARGS) { return(sglue2(0,CALLGLUE,"bitcoinrpc","setaccount","address",params[0],"account",params[1])); } @@ -536,7 +536,7 @@ struct RPC_info { char *name; char *(*rpcfunc)(RPCARGS); int32_t flag0,remotefla { "getnewaddress", &getnewaddress, true, false }, { "getnewpubkey", &makekeypair, true, false }, { "getaccountaddress", &getaccountaddress, true, false }, - { "setaccount", &setaccount, true, false }, + { "setaccount", &setaccountrpc, true, false }, { "getaccount", &getaccount, false, false }, { "getaddressesbyaccount", &getaddressesbyaccount, true, false }, { "sendtoaddress", &sendtoaddress, false, false }, diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c new file mode 100755 index 000000000..4e9a92dea --- /dev/null +++ b/iguana/iguana_sign.c @@ -0,0 +1,775 @@ +/****************************************************************************** + * 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" + +void iguana_addscript(struct iguana_info *coin,cJSON *dest,uint8_t *script,int32_t scriptlen,char *fieldname) +{ + char *scriptstr,scriptbuf[8192+256]; int32_t len; cJSON *scriptobj; + if ( scriptlen < 0 ) + return; + if ( scriptlen > sizeof(scriptbuf) ) + len = (scriptlen << 1) + 256, scriptstr = malloc(len); + else scriptstr = scriptbuf, len = sizeof(scriptbuf); + init_hexbytes_noT(scriptstr,script,scriptlen); + if ( strcmp(fieldname,"coinbase") == 0 ) + jaddstr(dest,"coinbase",scriptstr); + else + { + scriptobj = cJSON_CreateObject(); + jaddstr(scriptobj,"hex",scriptstr); + iguana_expandscript(coin,scriptstr,len,script,scriptlen); + if ( scriptstr[0] != 0 ) + jaddstr(scriptobj,"asm",scriptstr); + if ( scriptstr != scriptbuf ) + free(scriptstr); + jadd(dest,fieldname,scriptobj); + } +} + +cJSON *iguana_vinjson(struct iguana_info *coin,struct iguana_msgvin *vin) +{ + char str[65]; int32_t vout; cJSON *json = cJSON_CreateObject(); + vout = vin->prev_vout; + jaddnum(json,"sequence",vin->sequence); + if ( vout < 0 && bits256_nonz(vin->prev_hash) == 0 ) + iguana_addscript(coin,json,vin->vinscript,vin->scriptlen,"coinbase"); + else + { + jaddstr(json,"txid",bits256_str(str,vin->prev_hash)); + jaddnum(json,"vout",vout); + if ( vin->scriptlen > 0 ) + iguana_addscript(coin,json,vin->vinscript,vin->scriptlen,"scriptSig"); + if ( vin->spendlen > 0 ) + iguana_addscript(coin,json,vin->spendscript,vin->spendlen,"scriptPub"); + } + return(json); +} + +int32_t iguana_vinparse(struct iguana_info *coin,int32_t rwflag,uint8_t *serialized,struct iguana_msgvin *msg) +{ + int32_t len = 0; + len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->prev_hash),msg->prev_hash.bytes); + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout); + len += iguana_rwvarint32(rwflag,&serialized[len],&msg->scriptlen); + if ( msg->scriptlen > IGUANA_MAXSCRIPTSIZE ) + { + printf("iguana_vinparse illegal scriptlen.%d\n",msg->scriptlen); + return(-1); + } + if ( rwflag == 0 ) + { + msg->vinscript = &serialized[len]; + len += msg->scriptlen; + } + else + { + if ( msg->scriptlen > 0 ) + { + memcpy(&serialized[len],msg->vinscript,msg->scriptlen); + len += msg->scriptlen; + } + } + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence); + if ( 0 ) + { + int32_t i; char str[65]; + for (i=0; iscriptlen; i++) + printf("%02x",msg->vinscript[i]); + printf(" prev_hash.(%s) vout.%d [%p] scriptlen.%d rwflag.%d\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->vinscript,msg->scriptlen,rwflag); + } + return(len); +} + +int32_t iguana_voutparse(int32_t rwflag,uint8_t *serialized,struct iguana_msgvout *msg) +{ + int32_t len = 0; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->value),&msg->value); + len += iguana_rwvarint32(rwflag,&serialized[len],&msg->pk_scriptlen); + if ( msg->pk_scriptlen > IGUANA_MAXSCRIPTSIZE ) + { + printf("iguana_voutparse illegal scriptlen.%d\n",msg->pk_scriptlen); + return(-1); + } + if ( rwflag == 0 ) + msg->pk_script = &serialized[len]; + else memcpy(&serialized[len],msg->pk_script,msg->pk_scriptlen); + if ( 0 ) + { + int32_t i; + for (i=0; ipk_scriptlen; i++) + printf("%02x",msg->pk_script[i]); + printf(" [%p] scriptlen.%d rwflag.%d %.8f\n",msg->pk_script,msg->pk_scriptlen,rwflag,dstr(msg->value)); + } + len += msg->pk_scriptlen; + return(len); +} + +int32_t iguana_parsevoutobj(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvout *vout,cJSON *voutobj) +{ + int32_t len = 0; cJSON *skey; char *hexstr; + memset(vout,0,sizeof(*vout)); + vout->value = jdouble(voutobj,"value") * SATOSHIDEN; + if ( (skey= jobj(voutobj,"scriptPubKey")) != 0 ) + { + if ( (hexstr= jstr(skey,"hex")) != 0 ) + { + len = (int32_t)strlen(hexstr) >> 1; + decode_hex(serialized,len,hexstr); + vout->pk_script = serialized; + vout->pk_scriptlen = len; + } + } + return(len); +} + +int32_t iguana_parsevinobj(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvin *vin,cJSON *vinobj) +{ + int32_t n,len = 0; char *hexstr,*spendstr = 0; cJSON *scriptjson; + memset(vin,0,sizeof(*vin)); + vin->prev_vout = -1; + vin->sequence = juint(vinobj,"sequence"); + if ( (hexstr= jstr(vinobj,"coinbase")) == 0 ) + { + vin->prev_hash = jbits256(vinobj,"txid"); + vin->prev_vout = jint(vinobj,"vout"); + if ( (scriptjson= jobj(vinobj,"scriptSig")) != 0 ) + hexstr = jstr(scriptjson,"hex"); + if ( (scriptjson= jobj(vinobj,"scriptPub")) != 0 ) + spendstr = jstr(scriptjson,"hex"); + } + if ( hexstr != 0 ) + { + len = (int32_t)strlen(hexstr) >> 1; + decode_hex(serialized,len,hexstr); + vin->vinscript = serialized; + vin->scriptlen = len; + serialized = &serialized[len]; + } //else printf("iguana_parsevinobj: hex script missing (%s)\n",jprint(vinobj,0)); + if ( spendstr != 0 ) + { + n = (int32_t)strlen(spendstr) >> 1; + decode_hex(serialized,n,spendstr); + vin->spendscript = serialized; + vin->spendlen = n; + len += n; + } + return(len); +} + +cJSON *iguana_voutjson(struct iguana_info *coin,struct iguana_msgvout *vout,int32_t txi,bits256 txid) +{ + // 035f1321ed17d387e4433b2fa229c53616057964af065f98bfcae2233c5108055e OP_CHECKSIG + char scriptstr[IGUANA_MAXSCRIPTSIZE+1],asmstr[2*IGUANA_MAXSCRIPTSIZE+1]; int32_t i,m,n,scriptlen,asmtype; struct vin_info *vp; + uint8_t space[8192]; cJSON *addrs,*skey,*json = cJSON_CreateObject(); + vp = calloc(1,sizeof(*vp)); + jaddnum(json,"value",dstr(vout->value)); + jaddnum(json,"n",txi); + //"scriptPubKey":{"asm":"OP_DUP OP_HASH160 5f69cb73016264270dae9f65c51f60d0e4d6fd44 OP_EQUALVERIFY OP_CHECKSIG","reqSigs":1,"type":"pubkeyhash","addresses":["RHyh1V9syARTf2pyxibz7v27D5paBeWza5"]} + if ( vout->pk_script != 0 && vout->pk_scriptlen*2+1 < sizeof(scriptstr) ) + { + memset(vp,0,sizeof(*vp)); + if ( (asmtype= iguana_calcrmd160(coin,asmstr,vp,vout->pk_script,vout->pk_scriptlen,txid,txi,0xffffffff)) >= 0 ) + { + skey = cJSON_CreateObject(); + scriptlen = iguana_scriptgen(coin,&m,&n,vp->coinaddr,space,asmstr,vp->rmd160,asmtype,vp,txi); + if ( asmstr[0] != 0 ) + jaddstr(skey,"asm",asmstr); + addrs = cJSON_CreateArray(); + if ( vp->N == 1 ) + { + if ( asmtype == 2 ) + { + jaddnum(skey,"reqSigs",1); + jaddstr(skey,"type","pubkeyhash"); + } + if ( vp->coinaddr[0] != 0 ) + jaddistr(addrs,vp->coinaddr); + } + else + { + jaddnum(skey,"reqSigs",vp->M); + for (i=0; iN; i++) + { + //btc_convrmd160(coinaddr,coin->chain->pubtype,V.signers[i].pubkey); + jaddistr(addrs,vp->signers[i].coinaddr); + } + } + jadd(skey,"addresses",addrs); + init_hexbytes_noT(scriptstr,vout->pk_script,vout->pk_scriptlen); + if ( scriptstr[0] != 0 ) + jaddstr(skey,"hex",scriptstr); + jadd(json,"scriptPubKey",skey); + } + } + return(json); +} + +int32_t iguana_rwmsgtx(struct iguana_info *coin,int32_t rwflag,cJSON *json,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,bits256 *txidp,char *vpnstr) +{ + int32_t i,n,len = 0; uint8_t *txstart = serialized; char txidstr[65]; cJSON *array=0; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->version),&msg->version); + if ( json != 0 ) + { + jaddnum(json,"version",msg->version); + array = cJSON_CreateArray(); + } + //printf("version.%d\n",msg->version); + if ( coin->chain->hastimestamp != 0 ) + { + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->timestamp),&msg->timestamp); + //char str[65]; printf("version.%d timestamp.%08x %u %s\n",msg->version,msg->timestamp,msg->timestamp,utc_str(str,msg->timestamp)); + if ( json != 0 ) + jaddnum(json,"timestamp",msg->timestamp); + } + //for (i=len; itx_in); + //printf(" tx_in.%08x\n",msg->tx_in); + if ( rwflag == 0 ) + { + if ( len + sizeof(struct iguana_msgvin)*msg->tx_in > maxsize ) + { + printf("len.%d + tx_in.%d > maxsize.%d\n",len,msg->tx_in,maxsize); + return(-1); + } + maxsize -= (sizeof(struct iguana_msgvin) * msg->tx_in); + msg->vins = (struct iguana_msgvin *)&serialized[maxsize]; + memset(msg->vins,0,sizeof(struct iguana_msgvin) * msg->tx_in); + } + for (i=0; itx_in; i++) + { + if ( (n= iguana_vinparse(coin,rwflag,&serialized[len],&msg->vins[i])) < 0 ) + return(-1); + //printf("vin.%d n.%d len.%d\n",i,n,len); + len += n; + if ( len > maxsize ) + { + printf("invalid tx_in.%d len.%d vs maxsize.%d\n",msg->tx_in,len,maxsize); + return(-1); + } + if ( array != 0 ) + jaddi(array,iguana_vinjson(coin,&msg->vins[i])); + } + if ( array != 0 ) + { + jadd(json,"vin",array); + jaddnum(json,"numvins",msg->tx_in); + array = cJSON_CreateArray(); + } + //for (i=len; itx_out); + //printf(" txout.%d\n",msg->tx_out); + if ( rwflag == 0 ) + { + if ( len + sizeof(struct iguana_msgvout)*msg->tx_out > maxsize ) + { + printf("len.%d + tx_in.%d > maxsize.%d\n",len,msg->tx_in,maxsize); + return(-1); + } + maxsize -= (sizeof(struct iguana_msgvout) * msg->tx_out); + msg->vouts = (struct iguana_msgvout *)&serialized[maxsize]; + memset(msg->vouts,0,sizeof(struct iguana_msgvout) * msg->tx_out); + } + for (i=0; itx_out; i++) + { + if ( (n= iguana_voutparse(rwflag,&serialized[len],&msg->vouts[i])) < 0 ) + return(-1); + len += n; + if ( len > maxsize ) + { + printf("invalid tx_out.%d len.%d vs maxsize.%d\n",msg->tx_out,len,maxsize); + return(-1); + } + if ( array != 0 ) + jaddi(array,iguana_voutjson(coin,&msg->vouts[i],i,*txidp)); + } + if ( array != 0 ) + { + jadd(json,"vout",array); + jaddnum(json,"numvouts",msg->tx_out); + } + len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->lock_time),&msg->lock_time); + //printf("lock_time.%08x\n",msg->lock_time); + if ( strcmp(coin->symbol,"VPN") == 0 ) + { + uint16_t ddosflag = 0; + len += iguana_rwnum(rwflag,&serialized[len],sizeof(ddosflag),&ddosflag); + for (i=0; serialized[len]!=0&&lenlock_time); + jaddnum(json,"size",len); + jaddbits256(json,"txid",*txidp); + //printf("TX.(%s) %p\n",jprint(json,0),json); + } + msg->allocsize = len; + return(len); +} + +bits256 iguana_parsetxobj(struct iguana_info *coin,int32_t *txstartp,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,cJSON *txobj) // json -> serialized + (msg,V) +{ + int32_t i,numvins,numvouts,len = 0; cJSON *array=0; bits256 txid; char vpnstr[64]; + memset(msg,0,sizeof(*msg)); + vpnstr[0] = 0; + if ( (msg->version= juint(txobj,"version")) == 0 ) + msg->version = 1; + if ( coin->chain->hastimestamp != 0 ) + { + if ( (msg->timestamp= juint(txobj,"timestamp")) == 0 ) + msg->timestamp = (uint32_t)time(NULL); + } + if ( (array= jarray(&numvins,txobj,"vin")) != 0 ) + { + msg->tx_in = numvins; + if ( len + sizeof(struct iguana_msgvin)*msg->tx_in > maxsize ) + return(msg->txid); + maxsize -= (sizeof(struct iguana_msgvin) * msg->tx_in); + msg->vins = (struct iguana_msgvin *)&serialized[maxsize]; + if ( msg->tx_in > 0 && msg->tx_in*sizeof(struct iguana_msgvin) < maxsize ) + { + for (i=0; itx_in; i++) + len += iguana_parsevinobj(coin,&serialized[len],maxsize,&msg->vins[i],jitem(array,i)); + } + } + if ( (array= jarray(&numvouts,txobj,"vout")) != 0 ) + { + msg->tx_out = numvouts; + if ( len + sizeof(struct iguana_msgvout)*msg->tx_out > maxsize ) + return(msg->txid); + maxsize -= (sizeof(struct iguana_msgvout) * msg->tx_out); + msg->vouts = (struct iguana_msgvout *)&serialized[maxsize]; + if ( msg->tx_out > 0 && msg->tx_out*sizeof(struct iguana_msgvout) < maxsize ) + { + for (i=0; itx_out; i++) + len += iguana_parsevoutobj(coin,&serialized[len],maxsize,&msg->vouts[i],jitem(array,i)); + } + } + msg->lock_time = juint(txobj,"locktime"); + msg->txid = jbits256(txobj,"txid"); + *txstartp = len; + if ( (msg->allocsize= iguana_rwmsgtx(coin,1,0,&serialized[len],maxsize-len,msg,&txid,vpnstr)) < 0 ) + { + memset(txid.bytes,0,sizeof(txid)); + printf("error parsing txobj\n"); + msg->allocsize = 0; + } + //char str[65]; printf("json -> %s\n",bits256_str(str,txid)); + return(txid); +} + +char *iguana_rawtxbytes(struct iguana_info *coin,cJSON *json,struct iguana_msgtx *msgtx) +{ + int32_t n; char *txbytes = 0,vpnstr[64]; uint8_t *serialized; + serialized = malloc(IGUANA_MAXPACKETSIZE); + vpnstr[0] = 0; + //char str[65]; printf("%d of %d: %s\n",i,msg.txn_count,bits256_str(str,tx.txid)); + if ( (n= iguana_rwmsgtx(coin,1,json,serialized,IGUANA_MAXPACKETSIZE,msgtx,&msgtx->txid,vpnstr)) > 0 ) + { + txbytes = malloc(n*2+1); + init_hexbytes_noT(txbytes,serialized,n); + } + free(serialized); + return(txbytes); +} + +cJSON *bitcoin_createtx(struct iguana_info *coin,uint32_t locktime) +{ + cJSON *json = cJSON_CreateObject(); + if ( locktime == 0 ) + { + jaddnum(json,"version",1); + jaddnum(json,"locktime",0); + } + else + { + jaddnum(json,"version",4); + jaddnum(json,"locktime",locktime); + } + if ( coin->chain->hastimestamp != 0 ) + jaddnum(json,"timestamp",time(NULL)); + jadd(json,"vin",cJSON_CreateArray()); + jadd(json,"vout",cJSON_CreateArray()); + return(json); +} + +cJSON *bitcoin_addoutput(struct iguana_info *coin,cJSON *txobj,uint8_t *paymentscript,int32_t len,uint64_t satoshis) +{ + char *hexstr; cJSON *item,*skey,*vouts = jduplicate(jobj(txobj,"vout")); + jdelete(txobj,"vout"); + item = cJSON_CreateObject(); + jaddnum(item,"value",dstr(satoshis)); + skey = cJSON_CreateObject(); + hexstr = malloc(len*2 + 1); + init_hexbytes_noT(hexstr,paymentscript,len); + jaddstr(skey,"hex",hexstr); + //printf("addoutput.(%s %s)\n",hexstr,jprint(skey,0)); + free(hexstr); + jadd(item,"scriptPubkey",skey); + jaddi(vouts,item); + jadd(txobj,"vout",vouts); + return(txobj); +} + +cJSON *bitcoin_addinput(struct iguana_info *coin,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequenceid,uint8_t *spendscript,int32_t spendlen,uint8_t *redeemscript,int32_t p2shlen) +{ + cJSON *item,*vins; char p2shscriptstr[IGUANA_MAXSCRIPTSIZE*2+1]; + vins = jduplicate(jobj(txobj,"vin")); + jdelete(txobj,"vin"); + item = cJSON_CreateObject(); + if ( spendscript != 0 && spendscript > 0 ) + iguana_addscript(coin,item,spendscript,spendlen,"scriptPubKey"); + if ( redeemscript != 0 && p2shlen > 0 ) + { + init_hexbytes_noT(p2shscriptstr,redeemscript,p2shlen); + jaddstr(item,"redeemScript",p2shscriptstr); + } + jaddbits256(item,"txid",txid); + jaddnum(item,"vout",vout); + jaddnum(item,"sequence",sequenceid); + jaddi(vins,item); + jadd(txobj,"vin",vins); + printf("addvin -> (%s)\n",jprint(txobj,0)); + return(txobj); +} + +char *bitcoin_json2hex(struct iguana_info *coin,bits256 *txidp,cJSON *txjson) +{ + int32_t txstart; uint8_t *serialized; struct iguana_msgtx msgtx; char *txbytes = 0; + serialized = malloc(IGUANA_MAXPACKETSIZE*1.5); + *txidp = iguana_parsetxobj(coin,&txstart,serialized,IGUANA_MAXPACKETSIZE*1.5,&msgtx,txjson); + if ( msgtx.allocsize > 0 ) + { + txbytes = malloc(msgtx.allocsize*2 + 1); + init_hexbytes_noT(txbytes,&serialized[txstart],msgtx.allocsize); + } else printf("bitcoin_txtest: zero msgtx allocsize.(%s)\n",jprint(txjson,0)); + free(serialized); + return(txbytes); +} + +cJSON *bitcoin_hex2json(struct iguana_info *coin,bits256 *txidp,struct iguana_msgtx *msgtx,char *txbytes) +{ + int32_t n,len; char vpnstr[64]; struct iguana_msgtx M; uint8_t *serialized; cJSON *txobj; + txobj = cJSON_CreateObject(); + if ( msgtx == 0 ) + { + msgtx = &M; + memset(msgtx,0,sizeof(M)); + } + len = (int32_t)strlen(txbytes) >> 1; + serialized = malloc(len + 32768); + decode_hex(serialized,len,txbytes); + vpnstr[0] = 0; + memset(txidp,0,sizeof(*txidp)); + printf("B bitcoin_hex2json len.%d\n",len); + if ( (n= iguana_rwmsgtx(coin,0,txobj,serialized,len + 32768,msgtx,txidp,vpnstr)) <= 0 ) + { + printf("error from rwmsgtx\n"); + free_json(txobj); + txobj = 0; + } + free(serialized); + return(txobj); +} + +int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighashsingle) +{ + bits256 txid,sigtxid,revsigtxid; uint8_t *sig,*pubkey; struct vin_info *vp; + char txidstr[128],bigstr[2560],coinaddr[64],vpnstr[64],str[65]; uint32_t suffixlen,sigsize,pubkeysize; + int32_t n2,i,j,k,plen,vini=0,flag,numvins,hashtype,retval,siglen,asmtype,numvouts; + numvouts = msgtx->tx_out; + vpnstr[0] = 0; + *signedtx = 0; + memset(signedtxidp,0,sizeof(*signedtxidp)); + numvins = msgtx->tx_in; + retval = -numvins; + for (vini=0; vinivins[vini].vinscript; + vp = &V[vini]; + sig = &msgtx->vins[vini].vinscript[1]; + siglen = msgtx->vins[vini].vinscript[0]; + vp->vin = msgtx->vins[vini]; + flag = 0; + for (k=0; k<2; k++) + { + asmtype = (k == 0) ? IGUANA_SCRIPT_76A988AC : IGUANA_SCRIPT_76AC; + if ( bitcoin_scriptget(coin,&hashtype,&sigsize,&pubkeysize,&suffixlen,vp,msgtx->vins[vini].vinscript,msgtx->vins[vini].scriptlen,asmtype) < 0 ) + { + printf("cant get script for (%s).v%d\n",bits256_str(str,vp->vin.prev_hash),vp->vin.prev_vout); + continue; + } + if ( sighashsingle != 0 && vini == 0 ) + { + msgtx->tx_out = 1; + hashtype = SIGHASH_SINGLE; + } else msgtx->tx_out = numvouts; + msgtx->vins[vini].spendscript = vp->spendscript; + msgtx->vins[vini].spendlen = vp->spendlen; + msgtx->vins[vini].sequence = vp->sequence; + for (j=0; jN; j++) + { + pubkey = vp->signers[j].pubkey; + if ( (plen= bitcoin_pubkeylen(pubkey)) < 0 ) + { + if ( bits256_nonz(vp->signers[j].privkey) > 0 ) + { + pubkey = vp->signers[j].pubkey; + bitcoin_pubkey33(pubkey,vp->signers[j].privkey); + plen = bitcoin_pubkeylen(pubkey); + } + if ( plen < 0 ) + { + printf("nopubkey for j.%d vini.%d plen.%d [%02x]\n",j,vini,plen,pubkey[0]); + continue; + } + } + bitcoin_address(coinaddr,coin->chain->pubtype,pubkey,plen); + n2 = iguana_rwmsgtx(coin,1,0,serialized,maxsize,msgtx,&txid,vpnstr); + if ( n2 > 0 ) + { + n2 += iguana_rwnum(1,&serialized[n2],sizeof(hashtype),&hashtype); + //printf("hashtype.%d [%02x]\n",hashtype,sig[siglen-1]); + revsigtxid = bits256_doublesha256(txidstr,serialized,n2); + for (i=0; isigners[j].privkey) != 0 ) + { + siglen = bitcoin_sign(vp->signers[j].sig,sizeof(vp->signers[j].sig),sigtxid.bytes,sizeof(sigtxid),vp->signers[j].privkey); + sig = vp->signers[j].sig; + sig[siglen++] = hashtype; + vp->signers[j].siglen = siglen; + msgtx->vins[vini].vinscript = calloc(1,siglen*2+256); // fix this memleak! + msgtx->vins[vini].scriptlen = bitcoin_scriptsig(coin,msgtx->vins[vini].vinscript,0,(const struct vin_info *)vp,msgtx); + //for (i=0; isigners[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) + { + init_hexbytes_noT(bigstr,serialized,n2); + printf("(%s) doesnt verify hash2.%s\n",bigstr,bits256_str(str,sigtxid)); + *signedtx = iguana_rawtxbytes(coin,0,msgtx); + *signedtxidp = msgtx->txid; + printf("SIG.%d ERROR %s\n",vini,*signedtx); + } + else + { + cJSON *txobj = cJSON_CreateObject(); + *signedtx = iguana_rawtxbytes(coin,txobj,msgtx); + *signedtxidp = msgtx->txid; + //printf("SIG.%d VERIFIED %s (%s)\n",vini,*signedtx,jprint(txobj,1)); + flag = 1; + break; + } + } else printf("bitcoin_verifyvins: vini.%d n2.%d\n",vini,n2); + } + if ( flag > 0 ) + { + retval++; + break; + } + if ( vp->type != IGUANA_SCRIPT_76A988AC && vp->type != IGUANA_SCRIPT_76AC ) + break; + } + } + return(retval); +} + +int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,char *rawtxstr,struct vin_info *V) +{ + int32_t len,maxsize,numvins,retval = -1; uint8_t *serialized,*serialized2; + struct iguana_msgtx msgtx; bits256 txid; char vpnstr[64]; + len = (int32_t)strlen(rawtxstr); + maxsize = len + 32768; + serialized = calloc(1,maxsize), serialized2 = calloc(1,maxsize); + len >>= 1; + vpnstr[0] = 0; + decode_hex(serialized,len,rawtxstr); + memset(&msgtx,0,sizeof(msgtx)); + if ( iguana_rwmsgtx(coin,0,0,serialized,maxsize,&msgtx,&txid,vpnstr) > 0 ) + { + numvins = msgtx.tx_in; + if ( bitcoin_verifyvins(coin,signedtxidp,signedtx,&msgtx,serialized2,maxsize,V,0) == 0 ) + retval = 0; + else printf("bitcoin_verifytx: bitcoin_verifyvins error\n"); + } else printf("bitcoin_verifytx: error iguana_rwmsgtx\n"); + free(serialized), free(serialized2); + return(retval); +} + +cJSON *iguana_signtx(struct iguana_info *coin,bits256 *txidp,char **signedtxp,struct bitcoin_spend *spend,cJSON *txobj) +{ + int32_t i,j; char *rawtxstr; struct vin_info V; bits256 txid; + for (i=0; inuminputs; i++) // N times less efficient, but for small number of inputs ok + { + if ( *signedtxp != 0 ) + { + if ( txobj != 0 ) + free_json(txobj); + txobj = bitcoin_hex2json(coin,&txid,0,*signedtxp); + free(*signedtxp); + } + if ( (rawtxstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 ) + { + memset(&V,0,sizeof(V)); + for (j=0; jinputs[i].privkeys)/sizeof(*spend->inputs[i].privkeys); j++) + { + if ( bits256_nonz(spend->inputs[i].privkeys[j]) != 0 ) + V.signers[j].privkey = spend->inputs[i].privkeys[j]; + } + if ( spend->inputs[i].spendlen > 0 ) + { + memcpy(V.spendscript,spend->inputs[i].spendscript,spend->inputs[i].spendlen); + V.spendlen = spend->inputs[i].spendlen; + } + V.sequence = spend->inputs[i].sequence; + //printf("json2hex.(%s)\n",rawtxstr); + bitcoin_verifytx(coin,txidp,signedtxp,rawtxstr,&V); + //printf("json2hex.(%s)\n",rawtxstr); + free(rawtxstr); + } else break; + } + if ( *signedtxp != 0 && i != spend->numinputs ) + free(*signedtxp), *signedtxp = 0; + return(txobj); +} + +#include "../includes/iguana_apidefs.h" +#include "../includes/iguana_apideclares.h" + +char *_setVsigner(struct iguana_info *coin,struct vin_info *V,int32_t ind,char *pubstr,char *wifstr) +{ + uint8_t addrtype; + decode_hex(V->signers[ind].pubkey,(int32_t)strlen(pubstr)/2,pubstr); + bitcoin_wif2priv(&addrtype,&V->signers[ind].privkey,wifstr); + if ( addrtype != coin->chain->pubtype ) + return(clonestr("{\"error\":\"invalid wifA\"}")); + else return(0); +} + +int32_t bitcoin_txaddspend(struct iguana_info *coin,cJSON *txobj,char *destaddress,double destamount) +{ + uint8_t outputscript[128],addrtype,rmd160[20]; int32_t scriptlen; + if ( bitcoin_validaddress(coin,destaddress) == 0 && destamount > 0. ) + { + bitcoin_addr2rmd160(&addrtype,rmd160,destaddress); + scriptlen = bitcoin_standardspend(outputscript,0,rmd160); + bitcoin_addoutput(coin,txobj,outputscript,scriptlen,destamount * SATOSHIDEN); + return(0); + } else return(-1); +} + +P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount,destaddress2,destamount2,M,N,pubA,wifA,pubB,wifB,pubC,wifC) +{ + struct vin_info V; uint8_t p2sh_rmd160[20],serialized[2096],spendscript[32]; int32_t spendlen; + char msigaddr[64],*retstr; cJSON *retjson,*txobj; struct iguana_info *active; + bits256 signedtxid; char *signedtx; + struct iguana_msgtx msgtx; + if ( (active= iguana_coinfind(activecoin)) == 0 ) + return(clonestr("{\"error\":\"activecoin isnt active\"}")); + if ( M > N || N > 3 ) + return(clonestr("{\"error\":\"illegal M or N\"}")); + memset(&V,0,sizeof(V)); + txobj = bitcoin_createtx(active,0); + if ( destaddress[0] != 0 && destamount > 0. ) + bitcoin_txaddspend(active,txobj,destaddress,destamount); + if ( destaddress2[0] != 0 && destamount2 > 0. ) + bitcoin_txaddspend(active,txobj,destaddress2,destamount2); + if ( pubA[0] != 0 && (retstr= _setVsigner(active,&V,0,pubA,wifA)) != 0 ) + return(retstr); + if ( N >= 2 && pubB[0] != 0 && (retstr= _setVsigner(active,&V,1,pubB,wifB)) != 0 ) + return(retstr); + if ( N == 3 && pubC[0] != 0 && (retstr= _setVsigner(active,&V,2,pubC,wifC)) != 0 ) + return(retstr); + V.M = M, V.N = N, V.type = IGUANA_SCRIPT_P2SH; + V.p2shlen = bitcoin_MofNspendscript(p2sh_rmd160,V.p2shscript,0,&V); + spendlen = bitcoin_p2shspend(spendscript,0,p2sh_rmd160); + bitcoin_addinput(active,txobj,vintxid,vinvout,0xffffffff,spendscript,spendlen,V.p2shscript,V.p2shlen); + bitcoin_address(msigaddr,active->chain->p2shtype,V.p2shscript,V.p2shlen); + retjson = cJSON_CreateObject(); + if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,&msgtx,serialized,sizeof(serialized),&V,0) == 0 ) + { + jaddstr(retjson,"result","msigtx"); + if ( signedtx != 0 ) + jaddstr(retjson,"signedtx",signedtx), free(signedtx); + jaddbits256(retjson,"txid",signedtxid); + } else jaddstr(retjson,"error","couldnt sign tx"); + jaddstr(retjson,"msigaddr",msigaddr); + return(jprint(retjson,1)); +} + +STRING_ARRAY_OBJ_STRING(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys,sighash) +{ + bits256 txid; char *privkeystr,*signedtx = 0; bits256 privkey; int32_t i,n,numinputs = 1; struct bitcoin_spend *spend; cJSON *txobj=0,*item,*retjson = cJSON_CreateObject(); + //printf("rawtx.(%s) vins.(%s) privkeys.(%s) sighash.(%s)\n",rawtx,jprint(vins,0),jprint(privkeys,0),sighash); + if ( sighash == 0 || sighash[0] == 0 ) + sighash = "ALL"; + if ( strcmp(sighash,"ALL") != 0 ) + jaddstr(retjson,"error","only sighash all supported for now"); + else + { + // need to mix and match privkeys with inputs[i] + signedtx = clonestr(rawtx); + if ( (numinputs= cJSON_GetArraySize(vins)) > 0 && (n= cJSON_GetArraySize(privkeys)) > 0 ) + { + spend = calloc(1,sizeof(*spend) + (sizeof(*spend->inputs) * numinputs)); + spend->numinputs = numinputs; + for (i=0; iinputs[0].privkeys[i] = privkey; + //if ( i < numinputs ) + // spend->inputs[i].privkeys[0] = privkey; + char str2[65]; printf("privkey.%s <- %s\n",bits256_str(str2,privkey),privkeystr); + } + } + txobj = iguana_signtx(coin,&txid,&signedtx,spend,txobj); + free(spend); + free_json(txobj); + if ( signedtx != 0 ) + { + jaddstr(retjson,"result",signedtx); + free(signedtx); + } + } + } + return(jprint(retjson,1)); +} + +#include "../includes/iguana_apiundefs.h" + diff --git a/iguana/iguana_spendvectors.c b/iguana/iguana_spendvectors.c new file mode 100755 index 000000000..c99e35222 --- /dev/null +++ b/iguana/iguana_spendvectors.c @@ -0,0 +1,1101 @@ +/****************************************************************************** + * 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" + +static inline int32_t _iguana_spendvectorconv(struct iguana_spendvector *ptr,struct iguana_unspent *u,int32_t numpkinds,int32_t hdrsi,uint32_t unspentind) +{ + uint32_t spent_pkind = 0; + if ( (spent_pkind= u->pkind) != 0 && spent_pkind < numpkinds ) + { + ptr->pkind = spent_pkind; + ptr->value = u->value; + ptr->tmpflag = 0; + return(spent_pkind); + } else printf("spendvectorconv [%d] u%d pkind.%u/num %u\n",hdrsi,unspentind,u->pkind,numpkinds); + return(0); +} + +uint32_t iguana_spendvectorconv(struct iguana_info *coin,struct iguana_spendvector *ptr,struct iguana_bundle *bp) +{ + static uint64_t count,converted,errs; + struct iguana_bundle *spentbp; struct iguana_unspent *spentU; uint32_t spent_pkind; + count++; + if ( 0 && (count % 1000000) == 0 ) + printf("iguana_spendvectorconv.[%llu] errs.%llu converted.%llu %.2f%%\n",(long long)count,(long long)errs,(long long)converted,100. * (long long)converted/count); + if ( ptr->tmpflag != 0 ) + { + if ( ptr->hdrsi >= 0 && ptr->hdrsi < coin->bundlescount && (spentbp= coin->bundles[ptr->hdrsi]) != 0 ) + { + spentU = (void *)(long)((long)spentbp->ramchain.H.data + spentbp->ramchain.H.data->Uoffset); + if ( (spent_pkind= _iguana_spendvectorconv(ptr,&spentU[ptr->unspentind],spentbp->ramchain.H.data->numpkinds,ptr->hdrsi,ptr->unspentind)) != 0 ) + converted++; + else printf("illegal [%d].u%u pkind.%u vs %u\n",ptr->hdrsi,ptr->unspentind,spent_pkind,spentbp->ramchain.H.data->numpkinds); + } else printf("illegal [%d].u%u\n",ptr->hdrsi,ptr->unspentind); + errs++; + return(0); + } //else printf("[%d] tmpflag.%d u%d %.8f p%u\n",ptr->hdrsi,ptr->tmpflag,ptr->unspentind,dstr(ptr->value),ptr->pkind); + return(ptr->pkind); +} + +int32_t iguana_spendvectorsave(struct iguana_info *coin,struct iguana_bundle *bp,struct iguana_ramchain *ramchain,struct iguana_spendvector *ptr,int32_t emit,int32_t n) +{ + int32_t i,retval = -1; FILE *fp; char fname[1024],str[65]; long fsize; bits256 zero,sha256; + if ( ptr == 0 || (bp->hdrsi != 0 && ptr == bp->ramchain.Xspendinds) ) + { + //printf("iguana_spendvectorsave.[%d] ptr.%p Xspendinds\n",bp->hdrsi,ptr); + return(0); + } + memset(zero.bytes,0,sizeof(zero)); + for (i=0; ihdrsi,i,emit,n); + return(-1); + } + sprintf(fname,"%s/%s/spends/%s.%d",GLOBAL_DBDIR,coin->symbol,bits256_str(str,bp->hashes[0]),bp->bundleheight); + vcalc_sha256(0,sha256.bytes,(void *)ptr,(int32_t)(sizeof(*ptr) * emit)); + 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), fp = 0; + bp->Xvalid = 0; + if ( iguana_Xspendmap(coin,ramchain,bp) < 0 ) + printf("error mapping Xspendmap.(%s)\n",fname); + else + { + printf("created.(%s) %p[%d]\n",fname,bp->ramchain.Xspendinds,bp->ramchain.numXspends); + retval = 0; + } + } + if ( fp != 0 ) + fclose(fp); + //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("iguana_spendvectors: Error creating.(%s)\n",fname); + return(retval); +} + +struct iguana_bundle *iguana_externalspent(struct iguana_info *coin,bits256 *prevhashp,uint32_t *unspentindp,struct iguana_ramchain *ramchain,int32_t spent_hdrsi,struct iguana_spend *s,int32_t prefetchflag) +{ + 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); + //printf("external X.%p %ld num.%d\n",X,(long)ramchain->H.data->Xoffset,(int32_t)ramchain->H.data->numexternaltxids); + sequenceid = s->sequenceid; + hdrsi = spent_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 ) + { + //double duration,startmillis = OS_milliseconds(); + if ( (tp= iguana_txidfind(coin,&height,&TX,prev_hash,spent_hdrsi-1)) != 0 ) + { + *unspentindp = unspentind = TX.firstvout + ((prev_vout > 0) ? prev_vout : 0); + hdrsi = height / coin->chain->bundlesize; + if ( hdrsi >= 0 && hdrsi < coin->bundlescount && (spentbp= coin->bundles[hdrsi]) != 0 ) + { + //printf("%s height.%d firstvout.%d prev.%d ->U%d\n",bits256_str(str,prev_hash),height,TX.firstvout,prev_vout,unspentind); + /*now = (uint32_t)time(NULL); + duration = (OS_milliseconds() - startmillis); + if ( 0 && ((uint64_t)coin->txidfind_num % 1000000) == 1 ) + printf("%p iguana_txidfind.[%.0f] ave %.2f micros, total %.2f seconds | duration %.3f millis\n",spentbp->ramchain.txbits,coin->txidfind_num,(coin->txidfind_totalmillis*1000.)/coin->txidfind_num,coin->txidfind_totalmillis/1000.,duration); + coin->txidfind_totalmillis += duration; + coin->txidfind_num += 1.;*/ + if ( 1 && coin->PREFETCHLAG > 0 ) + { + if ( spentbp->lastprefetch == 0 ) + { + iguana_ramchain_prefetch(coin,&spentbp->ramchain,prefetchflag); + spentbp->lastprefetch = (uint32_t)time(NULL); + } + /*else if ( 0 && (rand() % IGUANA_NUMHELPERS) == 0 && (duration > 10 || duration > (10 * coin->txidfind_totalmillis)/coin->txidfind_num) ) + { + printf("slow txidfind %.2f vs %.2f prefetch[%d] from.[%d] lag.%ld last.%u\n",duration,coin->txidfind_totalmillis/coin->txidfind_num,spentbp->hdrsi,ramchain->height/coin->chain->bundlesize,time(NULL) - spentbp->lastprefetch,spentbp->lastprefetch); + iguana_ramchain_prefetch(coin,ramchain,1); + //spentbp->lastprefetch = now; + }*/ + } + } + else + { + printf("illegal hdrsi.%d prev_hash.(%s) for bp.[%d]\n",hdrsi,bits256_str(str,prev_hash),spent_hdrsi); + exit(-1); + } + } + else + { + printf("cant find prev_hash.(%s) for bp.[%d]\n",bits256_str(str,prev_hash),spent_hdrsi); + if ( spent_hdrsi < coin->current->hdrsi ) + { + iguana_bundleremove(coin,spent_hdrsi,1); + exit(-1); + } + coin->RTdatabad = 1; + return(0); + } + } else printf("external spent unexpected nonz unspentind [%d]\n",spent_hdrsi); + } + if ( (spentbp= coin->bundles[hdrsi]) == 0 || hdrsi > spent_hdrsi ) + printf("illegal hdrsi.%d when [%d] spentbp.%p\n",hdrsi,spent_hdrsi,spentbp); + 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); + else return(spentbp); + iguana_bundleremove(coin,spent_hdrsi,1); + exit(-1); + return(0); +} + +struct iguana_bundle *iguana_fastexternalspent(struct iguana_info *coin,bits256 *prevhashp,uint32_t *unspentindp,struct iguana_ramchain *ramchain,int32_t spent_hdrsi,struct iguana_spend *s) +{ + int32_t prev_vout,height,hdrsi,unspentind; uint32_t ind; + struct iguana_txid *T; bits256 *X; bits256 prev_hash; struct iguana_ramchaindata *rdata; + if ( (rdata= ramchain->H.data) == 0 ) + return(0); + hdrsi = spent_hdrsi; + *unspentindp = 0; + memset(prevhashp,0,sizeof(*prevhashp)); + if ( (prev_vout= s->prevout) >= 0 ) + { + ind = s->spendtxidind & ~(1 << 31); + if ( s->external != 0 ) + { + if ( ind < rdata->numexternaltxids ) + { + char str[65]; //double duration,startmillis = OS_milliseconds(); + X = (void *)(long)((long)rdata + rdata->Xoffset); + *prevhashp = prev_hash = X[ind]; + if ( (unspentind= iguana_unspentindfind(coin,&height,prev_hash,prev_vout,spent_hdrsi-1)) != 0 ) + //if ( (firstvout= iguana_txidfastfind(coin,&height,prev_hash,spent_hdrsi-1)) >= 0 ) + { + /*duration = (OS_milliseconds() - startmillis); + if ( ((uint64_t)coin->txidfind_num % 100) == 1 ) + printf("[%d] iguana_fasttxidfind.[%.0f] ave %.2f micros, total %.2f seconds | duration %.3f millis\n",spent_hdrsi,coin->txidfind_num,(coin->txidfind_totalmillis*1000.)/coin->txidfind_num,coin->txidfind_totalmillis/1000.,duration); + coin->txidfind_totalmillis += duration; + coin->txidfind_num += 1.;*/ + *unspentindp = unspentind;//firstvout + prev_vout; + hdrsi = height / coin->chain->bundlesize; + if ( hdrsi >= 0 && hdrsi < coin->bundlescount ) + return(coin->bundles[hdrsi]); + } + else + { + printf("couldnt fastfind (%s)\n",bits256_str(str,prev_hash)); + } + } else return(0); + } + else if ( ind < rdata->numtxids ) + { + T = (void *)(long)((long)rdata + rdata->Toffset); + *prevhashp = T[ind].txid; + *unspentindp = T[ind].firstvout + s->prevout; + return(coin->bundles[hdrsi]); + } + } + return(0); +} + +int32_t iguana_spendvectors(struct iguana_info *coin,struct iguana_bundle *bp,struct iguana_ramchain *ramchain,int32_t starti,int32_t numblocks,int32_t convertflag,int32_t iterate) +{ + static uint64_t total,emitted; + int32_t iter,spendind,n=0,txidind,errs=0,emit=0,i,j,k; double startmillis; bits256 prevhash; + uint32_t spent_unspentind,spent_pkind,now,starttime; struct iguana_ramchaindata *rdata; + struct iguana_bundle *spentbp; struct iguana_blockRO *B; struct iguana_spendvector *ptr; + struct iguana_unspent *u,*spentU; struct iguana_txid *T; char str[65]; + struct iguana_spend *S,*s; //void *fastfind = 0; + //printf("iguana_spendvectors.[%d] gen.%d ramchain data.%p txbits.%p\n",bp->hdrsi,bp->bundleheight,ramchain->H.data,ramchain->txbits); + if ( (rdata= ramchain->H.data) == 0 || (n= rdata->numspends) < 1 ) + { + printf("iguana_spendvectors.[%d]: no rdata.%p %d\n",bp->hdrsi,rdata,n); + return(0); + } + B = (void *)(long)((long)rdata + rdata->Boffset); + S = (void *)(long)((long)rdata + rdata->Soffset); + T = (void *)(long)((long)rdata + rdata->Toffset); + if ( ramchain->Xspendinds != 0 ) + { + bp->tmpspends = ramchain->Xspendinds; + bp->numtmpspends = ramchain->numXspends; + bp->utxofinish = (uint32_t)time(NULL); + bp->balancefinish = 0; + //printf("iguana_spendvectors.[%d]: already have Xspendinds[%d]\n",bp->hdrsi,ramchain->numXspends); + return(0); + } + ptr = mycalloc('x',sizeof(*ptr),n); + total += n; + startmillis = OS_milliseconds(); + if ( 0 && strcmp(coin->symbol,"BTC") == 0 ) + printf("start UTXOGEN.%d max.%d ptr.%p millis.%.3f\n",bp->bundleheight,n,ptr,startmillis); + starttime = (uint32_t)time(NULL); + iguana_ramchain_prefetch(coin,&bp->ramchain,3); + for (iter=0; iter<=iterate; iter++) + { + if ( iterate != 0 ) + { + //fastfind = coin->fast[iter]; + //coin->fast[iter] = calloc(1,coin->fastsizes[iter]); + //memcpy(coin->fast[iter],fastfind,coin->fastsizes[iter]); + } + txidind = B[starti].firsttxidind; + spendind = B[starti].firstvin; + for (i=starti; icurrent && (spendind % 10000) == 0 ) + printf("iter.%02x [%-3d:%4d] spendvectors elapsed t.%-3d spendind.%d\n",iter,bp->hdrsi,i,(uint32_t)time(NULL)-starttime,spendind); +#endif + u = 0; + spentbp = 0; + s = &S[spendind]; + if ( s->external != 0 && s->prevout >= 0 ) + { + if ( coin->fastfind != 0 ) + { + spentbp = iguana_fastexternalspent(coin,&prevhash,&spent_unspentind,ramchain,bp->hdrsi,s); + } + else if ( spentbp == 0 ) + { + if ( (spentbp= iguana_externalspent(coin,&prevhash,&spent_unspentind,ramchain,bp->hdrsi,s,2)) != 0 ) + { + if ( coin->fastfind != 0 ) + printf("found prevhash using slow, not fast\n"); + } + } + if ( iterate != 0 && (spentbp == 0 || spentbp->hdrsi != iter) ) + continue; + if ( bits256_nonz(prevhash) == 0 ) + continue; + if ( spentbp != 0 && spentbp->ramchain.H.data != 0 ) + { + if ( spentbp == bp ) + { + char str[65]; + printf("unexpected spendbp: height.%d bp.[%d] U%d <- S%d.[%d] [ext.%d %s prev.%d]\n",bp->bundleheight+i,spentbp->hdrsi,spent_unspentind,spendind,bp->hdrsi,s->external,bits256_str(str,prevhash),s->prevout); + errs++; + break; + } + if ( convertflag != 0 ) + { + if ( coin->PREFETCHLAG > 0 && now >= spentbp->lastprefetch+coin->PREFETCHLAG ) + { + printf("prefetch[%d] from.[%d] lag.%d\n",spentbp->hdrsi,bp->hdrsi,now - spentbp->lastprefetch); + iguana_ramchain_prefetch(coin,&spentbp->ramchain,2); + spentbp->lastprefetch = now; + } + spentU = (void *)(long)((long)spentbp->ramchain.H.data + spentbp->ramchain.H.data->Uoffset); + u = &spentU[spent_unspentind]; + if ( (spent_pkind= u->pkind) != 0 && spent_pkind < spentbp->ramchain.H.data->numpkinds ) + { + memset(&ptr[emit],0,sizeof(ptr[emit])); + if ( (ptr[emit].unspentind= spent_unspentind) != 0 && spentbp->hdrsi < bp->hdrsi ) + { + ptr[emit].fromheight = bp->bundleheight + i; + ptr[emit].hdrsi = spentbp->hdrsi; + ptr[emit].pkind = spent_pkind; + ptr[emit].value = u->value; + //printf("ht.%d [%d] SPENDVECTOR u%d %.8f p%u\n",ptr[emit].fromheight,ptr[emit].hdrsi,ptr[emit].unspentind,dstr(ptr[emit].value),ptr[emit].pkind); + //printf("(%d u%d).%d ",spentbp->hdrsi,unspentind,emit); + emit++; + } + else + { + printf("spendvectors: null unspentind for spendind.%d hdrsi.%d [%d]\n",spendind,spentbp->hdrsi,bp->hdrsi); + errs++; + break; + } + } + else + { + errs++; + printf("spendvectors: unresolved spendind.%d hdrsi.%d\n",spendind,bp->hdrsi); + break; + } + } + else + { + memset(&ptr[emit],0,sizeof(ptr[emit])); + ptr[emit].hdrsi = spentbp->hdrsi; + ptr[emit].unspentind = spent_unspentind; + ptr[emit].fromheight = bp->bundleheight + i; + ptr[emit].tmpflag = 1; + if ( 0 && bp == coin->current ) + printf("fromht.%d spends [%d] TMPVECTOR u%d s%u\n",ptr[emit].fromheight,ptr[emit].hdrsi,ptr[emit].unspentind,spendind); + emit++; + } + } + else + { + errs++; + printf("spendvectors: error resolving external spendind.%d hdrsi.%d\n",spendind,bp->hdrsi); + break; + } + } + } + } + } + /*if ( iterate != 0 ) + { + free(coin->fast[iter]); + coin->fast[iter] = fastfind; + }*/ + if ( txidind != ramchain->H.data->numtxids && txidind != ramchain->H.txidind ) + { + printf("spendvectors: numtxid.%d != bp numtxids %d/%d\n",txidind,ramchain->H.txidind,ramchain->H.data->numtxids); + errs++; + } + if ( spendind != ramchain->H.data->numspends && spendind != ramchain->H.spendind ) + { + printf("spendvectors: spendind.%d != bp numspends %d/%d\n",spendind,ramchain->H.spendind,ramchain->H.data->numspends); + errs++; + } + } + if ( errs == 0 && emit >= 0 ) + { + emitted += emit; + if ( convertflag == 0 ) + { + if ( bp->tmpspends != 0 ) + { + if ( bp->tmpspends != ramchain->Xspendinds && emit > 0 ) + { + // printf("spendvectors: RT [%d] numtmpspends.%d vs starti.%d emit.%d\n",bp->hdrsi,bp->numtmpspends,starti,emit); + bp->tmpspends = myrealloc('x',bp->tmpspends,sizeof(*ptr)*bp->numtmpspends,sizeof(*ptr)*(bp->numtmpspends+emit)); + memcpy(&bp->tmpspends[bp->numtmpspends],ptr,sizeof(*ptr)*emit); + bp->numtmpspends += emit; + } + } + else if ( emit > 0 ) + { + bp->tmpspends = myrealloc('x',ptr,sizeof(*ptr)*n,sizeof(*ptr)*emit); + bp->numtmpspends = emit; + //printf("ALLOC tmpspends.[%d]\n",bp->hdrsi); + ptr = 0; + } + if ( 0 && bp == coin->current ) + printf("spendvectors.[%d]: tmpspends.%p[%d] after += emit.%d X.%p\n",bp->hdrsi,bp->tmpspends,bp->numtmpspends,emit,bp->ramchain.Xspendinds); + } else errs = -iguana_spendvectorsave(coin,bp,ramchain,ptr!=0?ptr:bp->tmpspends,emit,n); + } + if ( ptr != 0 ) + myfree(ptr,sizeof(*ptr) * n); + //if ( bp != coin->current ) + printf("UTXO [%4d].%-6d dur.%-2d [milli %8.3f] vectors %-6d err.%d [%5.2f%%] %7d %9s of %d\n",bp->hdrsi,bp->numtmpspends,(uint32_t)time(NULL)-starttime,OS_milliseconds()-startmillis,spendind,errs,100.*(double)emitted/(total+1),emit,mbstr(str,sizeof(*ptr) * emit),n); + return(-errs); +} + +int32_t iguana_balancegen(struct iguana_info *coin,int32_t incremental,struct iguana_bundle *bp,int32_t starti,int32_t endheight,int32_t startemit) +{ + uint32_t spent_unspentind,spent_pkind,txidind,h,i,j,endi,k,now; uint64_t spent_value; + struct iguana_ramchain *ramchain; struct iguana_ramchaindata *rdata; + struct iguana_spendvector *spend; struct iguana_unspent *spentU,*u; struct iguana_spendvector *Xspendinds; + struct iguana_txid *T; struct iguana_blockRO *B; struct iguana_bundle *spentbp; + int32_t spent_hdrsi,spendind,n,numXspends,errs=0,emit=0; struct iguana_spend *S,*s; + ramchain = &bp->ramchain; //(bp == coin->current) ? &coin->RTramchain : &bp->ramchain; + if ( (rdata= ramchain->H.data) == 0 || (n= ramchain->H.data->numspends) < 1 ) + return(-1); + S = (void *)(long)((long)rdata + rdata->Soffset); + B = (void *)(long)((long)rdata + rdata->Boffset); + T = (void *)(long)((long)rdata + rdata->Toffset); + numXspends = ramchain->numXspends; + if ( (Xspendinds= ramchain->Xspendinds) == 0 ) + { + numXspends = bp->numtmpspends; + if ( (Xspendinds= bp->tmpspends) == 0 ) + { + //printf("iguana_balancegen.%d: no Xspendinds[%d]\n",bp->hdrsi,numXspends); + //return(-1); + } + } + endi = (endheight % bp->n); + txidind = B[starti].firsttxidind; + spendind = B[starti].firstvin; + emit = startemit; + if ( coin->RTheight == 0 || bp->bundleheight+bp->n < coin->RTheight ) + fprintf(stderr,"BALANCEGEN.[%d] %p[%d] starti.%d s%d <-> endi.%d s%d startemit.%d\n",bp->hdrsi,Xspendinds,numXspends,starti,spendind,endi,B[endi].firstvin+B[endi].numvins,startemit); + for (i=starti; i<=endi; i++) + { + now = (uint32_t)time(NULL); + if ( 0 && bp == coin->current ) + printf("hdrs.[%d] B[%d] 1st txidind.%d txn_count.%d firstvin.%d firstvout.%d\n",bp->hdrsi,i,B[i].firsttxidind,B[i].txn_count,B[i].firstvin,B[i].firstvout); + if ( txidind != B[i].firsttxidind || spendind != B[i].firstvin ) + { + printf("balancegen: txidind %u != %u B[%d].firsttxidind || spendind %u != %u B[%d].firstvin errs.%d\n",txidind,B[i].firsttxidind,i,spendind,B[i].firstvin,i,errs); + return(-1); + } + for (j=0; jcurrent ) + printf("starti.%d txidind.%d txi.%d numvins.%d spendind.%d\n",i,txidind,j,T[txidind].numvins,spendind); + for (k=0; kexternal != 0 && s->prevout >= 0 ) + { + if ( emit >= numXspends ) + errs++; + else if ( Xspendinds != 0 ) + { + spend = &Xspendinds[emit++]; + spent_unspentind = spend->unspentind; + spent_value = spend->value; + spent_pkind = spend->pkind; + spent_hdrsi = spend->hdrsi; + h = spend->fromheight; + } + if ( 0 && bp == coin->current ) + printf("external prevout.%d (emit.%d numX.%d) %p u%d p%d errs.%d spent_hdrsi.%d s%u\n",s->prevout,emit,numXspends,Xspendinds,spent_unspentind,spent_pkind,errs,spent_hdrsi,spendind); + } + else if ( s->prevout >= 0 ) + { + h = bp->bundleheight + i; + spent_hdrsi = bp->hdrsi; + if ( s->spendtxidind != 0 && s->spendtxidind < rdata->numtxids ) + { + spent_unspentind = T[s->spendtxidind].firstvout + s->prevout; + spentU = (void *)(long)((long)rdata + rdata->Uoffset); + u = &spentU[spent_unspentind]; + if ( (spent_pkind= u->pkind) != 0 && spent_pkind < rdata->numpkinds ) + spent_value = u->value; + /*found spend d9151... txidind.1083097 [202] s3163977 + //found spend d9151... txidind.1083097 [202] s4033628 + if ( spent_hdrsi == 202 && (spendind == 3163977 || spendind == 4033628) ) + printf("internal spend.%d spendtxidind.%d 1st.%d U.(prevout.%d u%u pkind.%u %.8f)\n",spendind,txidind,T[s->spendtxidind].firstvout,s->prevout,spent_unspentind,u->pkind,dstr(u->value));*/ + } + else //if ( i > 0 || j > 0 || k > 0 ) + { + printf("iguana_balancegen [%d] txidind overflow %u vs %u (%d %d %d)\n",bp->hdrsi,s->spendtxidind,rdata->numtxids,i,j,k); + errs++; + } + } + else continue; + spentbp = 0; + if ( (spentbp= coin->bundles[spent_hdrsi]) != 0 && spent_unspentind > 0 && spent_pkind > 0 ) + { + if ( 0 && bp == coin->current ) + printf("[%d] spendind.%u -> [%d] u%d\n",bp->hdrsi,spendind,spent_hdrsi,spent_unspentind); + if ( iguana_volatileupdate(coin,incremental,spentbp == coin->current ? &coin->RTramchain : &spentbp->ramchain,spent_hdrsi,spent_unspentind,spent_pkind,spent_value,spendind,h) < 0 ) + errs++; + } + else //if ( Xspendinds != 0 ) + { + errs++; + printf("iguana_balancegen: spendind.%u external.%d error spentbp.%p with unspentind.%d pkind.%u [%d] (%d %d %d)\n",spendind,s->external,spentbp,spent_unspentind,spent_pkind,spent_hdrsi,i,j,k); + } + } + } + } + if ( txidind != bp->ramchain.H.data->numtxids && (bp != coin->current || txidind != ramchain->H.txidind) ) + { + printf("numtxid.%d != bp numtxids %d/%d\n",txidind,bp->ramchain.H.txidind,bp->ramchain.H.data->numtxids); + errs++; + } + if ( spendind != ramchain->H.data->numspends && (bp != coin->current || spendind != ramchain->H.spendind) ) + { + printf("spendind.%d != bp numspends %d/%d\n",spendind,bp->ramchain.H.spendind,bp->ramchain.H.data->numspends); + errs++; + } + if ( emit != numXspends ) + { + printf("iguana_balancegen: emit %d != %d ramchain->numXspends\n",emit,numXspends); + errs++; + } + if ( errs == 0 ) + bp->balancefinish = (uint32_t)time(NULL); + //printf(">>>>>>>> balances.%d done errs.%d spendind.%d\n",bp->hdrsi,errs,n); + return(-errs); +} + +void iguana_truncatebalances(struct iguana_info *coin) +{ + int32_t i; struct iguana_bundle *bp; + for (i=0; ibalanceswritten; i++) + { + if ( (bp= coin->bundles[i]) != 0 ) + { + bp->balancefinish = 0; + bp->Xvalid = 0; + iguana_volatilespurge(coin,&bp->ramchain); + } + } + coin->balanceswritten = 0; +} + +int32_t iguana_volatilesinit(struct iguana_info *coin) +{ + bits256 balancehash,allbundles; struct iguana_utxo *Uptr; struct iguana_account *Aptr; + struct sha256_vstate vstate,bstate; int32_t i,from_ro,numpkinds,numunspents; struct iguana_bundle *bp; struct iguana_block *block; + uint32_t crc,filecrc; FILE *fp; char crcfname[512],str[65],str2[65],buf[2048]; + from_ro = 1; + for (i=0; ibalanceswritten; i++) + { + if ( (bp= coin->bundles[i]) == 0 ) + break; + if ( bp->emitfinish <= 1 || (i > 0 && bp->utxofinish <= 1) ) + { + printf("hdrsi.[%d] emitfinish.%u utxofinish.%u\n",i,bp->emitfinish,bp->utxofinish); + break; + } + iguana_volatilesmap(coin,&bp->ramchain); + if ( from_ro != 0 && (bp->ramchain.from_ro == 0 || (bp->hdrsi > 0 && bp->ramchain.from_roX == 0) || bp->ramchain.from_roA == 0 || bp->ramchain.from_roU == 0) ) + { + printf("from_ro.[%d] %d %d %d %d\n",bp->hdrsi,bp->ramchain.from_ro,bp->ramchain.from_roX,bp->ramchain.from_roA,bp->ramchain.from_roU); + from_ro = 0; + } + } + if ( i < coin->balanceswritten-1 ) + { + printf("TRUNCATE balances written.%d -> %d\n",coin->balanceswritten,i); + iguana_truncatebalances(coin); + } + else + { + coin->balanceswritten = i; + //printf("verify crc and sha256 hash for %d of %d\n",i,coin->balanceswritten); + vupdate_sha256(balancehash.bytes,&vstate,0,0); + vupdate_sha256(allbundles.bytes,&bstate,0,0); + filecrc = 0; + sprintf(crcfname,"%s/%s/balancecrc.%d",GLOBAL_DBDIR,coin->symbol,coin->balanceswritten); + if ( (fp= fopen(crcfname,"rb")) != 0 ) + { + if ( fread(&filecrc,1,sizeof(filecrc),fp) != sizeof(filecrc) ) + filecrc = 0; + else if ( fread(&balancehash,1,sizeof(balancehash),fp) != sizeof(balancehash) ) + filecrc = 0; + else if ( memcmp(&balancehash,&coin->balancehash,sizeof(balancehash)) != 0 ) + filecrc = 0; + else if ( fread(&allbundles,1,sizeof(allbundles),fp) != sizeof(allbundles) ) + filecrc = 0; + else if ( memcmp(&allbundles,&coin->allbundles,sizeof(allbundles)) != 0 ) + filecrc = 0; + fclose(fp); + } + if ( filecrc != 0 ) + printf("have filecrc.%08x for %s milli.%.0f from_ro.%d\n",filecrc,bits256_str(str,balancehash),OS_milliseconds(),from_ro); + if ( from_ro == 0 || filecrc == 0 ) + { + if ( filecrc == 0 ) + { + vupdate_sha256(balancehash.bytes,&vstate,0,0); + vupdate_sha256(allbundles.bytes,&bstate,0,0); + } + for (i=crc=0; ibalanceswritten; i++) + { + numpkinds = numunspents = 0; + Aptr = 0, Uptr = 0; + if ( (bp= coin->bundles[i]) != 0 && bp->ramchain.H.data != 0 && (numpkinds= bp->ramchain.H.data->numpkinds) > 0 && (numunspents= bp->ramchain.H.data->numunspents) > 0 && (Aptr= bp->ramchain.A2) != 0 && (Uptr= bp->ramchain.Uextras) != 0 ) + { + if ( (bp->bundleheight % 10000) == 0 ) + fprintf(stderr,"."); + if ( filecrc == 0 ) + { + vupdate_sha256(balancehash.bytes,&vstate,(void *)Aptr,sizeof(*Aptr) * numpkinds); + vupdate_sha256(balancehash.bytes,&vstate,(void *)Uptr,sizeof(*Uptr) * numunspents); + vupdate_sha256(allbundles.bytes,&bstate,(void *)bp->hashes,sizeof(bp->hashes[0]) * bp->n); + } + crc = calc_crc32(crc,(void *)Aptr,(int32_t)(sizeof(*Aptr) * numpkinds)); + crc = calc_crc32(crc,(void *)Uptr,(int32_t)(sizeof(*Uptr) * numunspents)); + crc = calc_crc32(crc,(void *)bp->hashes,(int32_t)(sizeof(bp->hashes[0]) * bp->n)); + } //else printf("missing hdrs.[%d] data.%p num.(%u %d) %p %p\n",i,bp->ramchain.H.data,numpkinds,numunspents,Aptr,Uptr); + } + } else crc = filecrc; + printf("millis %.0f from_ro.%d written.%d crc.%08x/%08x balancehash.(%s) vs (%s)\n",OS_milliseconds(),from_ro,coin->balanceswritten,crc,filecrc,bits256_str(str,balancehash),bits256_str(str2,coin->balancehash)); + if ( (filecrc != 0 && filecrc != crc) || memcmp(balancehash.bytes,coin->balancehash.bytes,sizeof(balancehash)) != 0 || memcmp(allbundles.bytes,coin->allbundles.bytes,sizeof(allbundles)) != 0 ) + { + printf("balancehash or crc.(%x %x) mismatch or allbundles.(%llx %llx) mismatch\n",crc,filecrc,(long long)allbundles.txid,(long long)coin->allbundles.txid); + iguana_truncatebalances(coin); + OS_removefile(crcfname,0); + } + else + { + printf("MATCHED balancehash numhdrsi.%d crc.%08x\n",coin->balanceswritten,crc); + if ( (fp= fopen(crcfname,"wb")) != 0 ) + { + if ( fwrite(&crc,1,sizeof(crc),fp) != sizeof(crc) || fwrite(&balancehash,1,sizeof(balancehash),fp) != sizeof(balancehash) || fwrite(&allbundles,1,sizeof(allbundles),fp) != sizeof(allbundles) ) + printf("error writing.(%s)\n",crcfname); + fclose(fp); + } + else + { + printf("volatileinit: cant create.(%s)\n",crcfname); + return(-1); + } + } + } + if ( (coin->RTheight= coin->balanceswritten * coin->chain->bundlesize) > coin->longestchain ) + coin->longestchain = coin->RTheight; + iguana_bundlestats(coin,buf,IGUANA_DEFAULTLAG); + if ( (bp= coin->bundles[coin->balanceswritten-1]) != 0 && (block= bp->blocks[bp->n-1]) != 0 ) + { + //char str[65]; + //printf("set hwmchain.%d <- %s %p\n",bp->bundleheight+bp->n-1,bits256_str(str,bp->hashes[bp->n-1]),block); + if ( block->height > coin->blocks.hwmchain.height ) + coin->blocks.hwmchain = *block; + } + //printf("end volatilesinit\n"); + if ( iguana_fastfindinit(coin) == 0 )//&& coin->PREFETCHLAG >= 0 ) + iguana_fastfindcreate(coin); + return(coin->balanceswritten); +} + +void iguana_initfinal(struct iguana_info *coin,bits256 lastbundle) +{ + int32_t i; struct iguana_bundle *bp; bits256 hash2; struct iguana_block *block; char hashstr[65]; + if ( bits256_nonz(lastbundle) > 0 ) + { + init_hexbytes_noT(hashstr,lastbundle.bytes,sizeof(bits256)); + printf("req lastbundle.(%s)\n",hashstr); + queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1); + } + for (i=0; ibundlescount-1; i++) + { + if ( (bp= coin->bundles[i]) == 0 || bp->emitfinish <= 1 ) + { + printf("initfinal break.[%d]: bp.%p or emit.%u utxofinish.%u\n",i,bp,bp!=0?bp->emitfinish:-1,bp!=0?bp->utxofinish:-1); + break; + } + if ( i == 0 ) + bp->utxofinish = bp->startutxo = (uint32_t)time(NULL); + } + if ( i < coin->bundlescount-1 ) + { + printf("spendvectors.[%d] max.%d missing, will regen all of them\n",i,coin->bundlescount-1); + for (i=0; ibundlescount-1; i++) + { + if ( (bp= coin->bundles[i]) != 0 ) + bp->startutxo = bp->utxofinish = 0; + } + } + else + { + for (i=0; ibundlescount-1; i++) + { + if ( (bp= coin->bundles[i]) != 0 ) + bp->converted = (uint32_t)time(NULL); + } + } + printf("i.%d bundlescount.%d\n",i,coin->bundlescount); + if ( coin->balanceswritten > 1 ) + coin->balanceswritten = iguana_volatilesinit(coin); + if ( coin->balanceswritten > 1 ) + { + for (i=0; ibalanceswritten; i++) + { + //printf("%d ",i); + iguana_validateQ(coin,coin->bundles[i]); + } + } + printf("i.%d balanceswritten.%d\n",i,coin->balanceswritten); + if ( coin->balanceswritten < coin->bundlescount ) + { + for (i=coin->balanceswritten; ibundlescount; i++) + { + if ( (bp= coin->bundles[i]) != 0 && bp->queued == 0 ) + { + //printf("%d ",i); + iguana_bundleQ(coin,bp,1000); + } + } + printf("iguana_bundlesQ %d to %d\n",coin->balanceswritten,coin->bundlescount); + } + if ( (coin->origbalanceswritten= coin->balanceswritten) > 0 ) + iguana_volatilesinit(coin); + iguana_savehdrs(coin); + iguana_fastlink(coin,coin->balanceswritten * coin->chain->bundlesize - 1); + iguana_walkchain(coin,0); + hash2 = iguana_blockhash(coin,coin->balanceswritten * coin->chain->bundlesize); + if ( bits256_nonz(hash2) != 0 && (block= iguana_blockfind("initfinal",coin,hash2)) != 0 ) + _iguana_chainlink(coin,block); +} + +int32_t iguana_balanceflush(struct iguana_info *coin,int32_t refhdrsi) +{ + int32_t hdrsi,numpkinds,iter,numhdrsi,i,numunspents,err; struct iguana_bundle *bp; + char fname[1024],fname2[1024],destfname[1024]; bits256 balancehash,allbundles; FILE *fp,*fp2; + struct iguana_utxo *Uptr; struct iguana_account *Aptr; struct sha256_vstate vstate,bstate; + vupdate_sha256(balancehash.bytes,&vstate,0,0); + numhdrsi = refhdrsi; + vupdate_sha256(balancehash.bytes,&vstate,0,0); + vupdate_sha256(allbundles.bytes,&bstate,0,0); + for (iter=0; iter<3; iter++) + { + for (hdrsi=0; hdrsibundles[hdrsi]) != 0 && bp->ramchain.H.data != 0 && (numpkinds= bp->ramchain.H.data->numpkinds) > 0 && (numunspents= bp->ramchain.H.data->numunspents) > 0 && (Aptr= bp->ramchain.A2) != 0 && (Uptr= bp->ramchain.Uextras) != 0 ) + { + sprintf(fname,"%s/%s/debits.%d_N%d",GLOBAL_TMPDIR,coin->symbol,bp->hdrsi,numhdrsi); + sprintf(fname2,"%s/%s/lastspends.%d_N%d",GLOBAL_TMPDIR,coin->symbol,bp->hdrsi,numhdrsi); + if ( iter == 0 ) + { + vupdate_sha256(balancehash.bytes,&vstate,(void *)Aptr,sizeof(*Aptr)*numpkinds); + vupdate_sha256(balancehash.bytes,&vstate,(void *)Uptr,sizeof(*Uptr)*numunspents); + vupdate_sha256(allbundles.bytes,&bstate,(void *)bp->hashes,sizeof(bp->hashes[0])*bp->n); + } + else if ( iter == 1 ) + { + if ( (fp= fopen(fname,"wb")) != 0 && (fp2= fopen(fname2,"wb")) != 0 ) + { + err = -1; + if ( fwrite(&numhdrsi,1,sizeof(numhdrsi),fp) == sizeof(numhdrsi) && fwrite(&numhdrsi,1,sizeof(numhdrsi),fp2) == sizeof(numhdrsi) && fwrite(balancehash.bytes,1,sizeof(balancehash),fp) == sizeof(balancehash) && fwrite(balancehash.bytes,1,sizeof(balancehash),fp2) == sizeof(balancehash) && fwrite(allbundles.bytes,1,sizeof(allbundles),fp) == sizeof(allbundles) && fwrite(allbundles.bytes,1,sizeof(allbundles),fp2) == sizeof(allbundles) ) + { + if ( fwrite(Aptr,sizeof(*Aptr),numpkinds,fp) == numpkinds ) + { + if ( fwrite(Uptr,sizeof(*Uptr),numunspents,fp2) == numunspents ) + { + err = 0; + printf("[%d] of %d saved (%s) and (%s)\n",hdrsi,numhdrsi,fname,fname2); + } + } + } + if ( err != 0 ) + { + printf("balanceflush.%s error iter.%d hdrsi.%d\n",coin->symbol,iter,hdrsi); + fclose(fp); + fclose(fp2); + return(-1); + } + fclose(fp), fclose(fp2); + } + else + { + printf("error opening %s or %s %p\n",fname,fname2,fp); + if ( fp != 0 ) + fclose(fp); + } + } + else if ( iter == 2 ) + { + sprintf(destfname,"%s/%s/accounts/debits.%d",GLOBAL_DBDIR,coin->symbol,bp->bundleheight); + if ( OS_copyfile(fname,destfname,1) < 0 ) + { + printf("balances error copying (%s) -> (%s)\n",fname,destfname); + return(-1); + } + sprintf(destfname,"%s/%s/accounts/lastspends.%d",GLOBAL_DBDIR,coin->symbol,bp->bundleheight); + if ( OS_copyfile(fname2,destfname,1) < 0 ) + { + printf("balances error copying (%s) -> (%s)\n",fname2,destfname); + return(-1); + } + printf("%s -> %s\n",fname,destfname); + OS_removefile(fname,0); + OS_removefile(fname2,0); + } + if ( bp->ramchain.allocatedA2 == 0 || bp->ramchain.allocatedU2 == 0 ) + { + printf("skip saving.[%d] files as not allocated\n",bp->hdrsi); + break; + } + } + else if ( hdrsi > 0 && (coin->current == 0 || hdrsi != coin->current->hdrsi) ) + { + printf("balanceflush iter.%d error loading [%d] Aptr.%p Uptr.%p numpkinds.%u numunspents.%u\n",iter,hdrsi,Aptr,Uptr,numpkinds,numunspents); + return(-1); + } + } + } + coin->allbundles = allbundles; + coin->balancehash = balancehash; + coin->balanceswritten = numhdrsi; + if ( 1 ) + { + for (hdrsi=0; hdrsibundles[hdrsi]) == 0 && bp != coin->current ) + { + iguana_volatilespurge(coin,&bp->ramchain); + if ( iguana_volatilesmap(coin,&bp->ramchain) != 0 ) + printf("error mapping bundle.[%d]\n",hdrsi); + } + } + char str[65]; printf("BALANCES WRITTEN for %d orig.%d bundles %s\n",coin->balanceswritten,coin->origbalanceswritten,bits256_str(str,coin->balancehash)); + if ( 0 && coin->balanceswritten > coin->origbalanceswritten+10 ) // strcmp(coin->symbol,"BTC") == 0 && + { + coin->active = 0; + coin->started = 0; + for (i=0; ipeers.active[i].dead = (uint32_t)time(NULL); +#ifdef __linux__ + char cmd[1024]; + sprintf(cmd,"mksquashfs %s/%s %s.%d -comp xz",GLOBAL_DBDIR,coin->symbol,coin->symbol,coin->balanceswritten); + if ( system(cmd) != 0 ) + printf("error system(%s)\n",cmd); + else + { + sprintf(cmd,"sudo umount %s/ro/%s",GLOBAL_DBDIR,coin->symbol); + if ( system(cmd) != 0 ) + printf("error system(%s)\n",cmd); + else + { + sprintf(cmd,"sudo mount %s.%d %s/ro/%s -t squashfs -o loop",coin->symbol,coin->balanceswritten,GLOBAL_DBDIR,coin->symbol); + if ( system(cmd) != 0 ) + printf("error system(%s)\n",cmd); + } + } +#endif + for (i=0; i<30; i++) + { + printf("need to exit, please restart after shutdown in %d seconds, or just ctrl-C\n",30-i); + sleep(1); + } + exit(-1); + } + coin->balanceswritten = iguana_volatilesinit(coin); + //printf("flush free\n"); + iguana_RTramchainfree(coin,bp); + return(coin->balanceswritten); +} + +int32_t iguana_spendvectorsaves(struct iguana_info *coin) +{ + int32_t i,j,n,iter; struct iguana_bundle *bp; + if ( coin->spendvectorsaved > 1 ) + return(0); + coin->spendvectorsaved = 1; + n = coin->bundlescount - 1; + //printf("SAVE SPEND VECTORS %d of %d\n",n,coin->bundlescount); + for (iter=0; iter<2; iter++) + { + for (i=0; ibundles[i]) != 0 ) + { + if ( iter == 0 ) + { + if ( bp->tmpspends != 0 )//bp->ramchain.Xspendinds == 0 && + { + for (j=0; jnumtmpspends; j++) + if ( bp->tmpspends[j].tmpflag != 0 ) + { + printf("vectorsave.[%d] vec.%d still has tmpflag\n",i,j); + return(-1); + } + } + } + else if ( iguana_spendvectorsave(coin,bp,&bp->ramchain,bp->tmpspends,bp->numtmpspends,bp->ramchain.H.data->numspends) == 0 ) + { + if ( bp->tmpspends != 0 && bp->numtmpspends > 0 && bp->tmpspends != bp->ramchain.Xspendinds ) + myfree(bp->tmpspends,sizeof(*bp->tmpspends) * bp->numtmpspends); + bp->numtmpspends = 0; + bp->tmpspends = 0; + } + } + } + } + coin->spendvectorsaved = (uint32_t)time(NULL); + return(0); +} + +int32_t iguana_spendvectorconvs(struct iguana_info *coin,struct iguana_bundle *spentbp,int32_t starti) +{ + struct iguana_bundle *bp; int16_t spent_hdrsi; uint32_t numpkinds; struct iguana_unspent *spentU; struct iguana_spendvector *vec; int32_t i,converted,j,n = coin->bundlescount; struct iguana_ramchain *ramchain; struct iguana_ramchaindata *rdata = 0; + if ( (rdata= spentbp->ramchain.H.data) == 0 ) + { + //if ( spentbp == coin->current ) + printf("iguana_spendvectorconvs: [%d] null rdata.%p\n",spentbp->hdrsi,rdata); + return(-1); + } + spent_hdrsi = spentbp->hdrsi; + ramchain = &spentbp->ramchain; + numpkinds = rdata->numpkinds; + spentU = (void *)(long)((long)rdata + rdata->Uoffset); + for (i=converted=0; ibundles[i]) != 0 && bp->tmpspends != 0 ) + { + for (j=0; jnumtmpspends; j++) + { + vec = &bp->tmpspends[j]; + if ( vec->hdrsi == spent_hdrsi ) + { + if ( vec->tmpflag == 0 ) + { + if ( bp->tmpspends != bp->ramchain.Xspendinds && bp != coin->current ) + printf("unexpected null tmpflag [%d] j.%d spentbp.[%d]\n",bp->hdrsi,j,spentbp->hdrsi); + } + else + { + if ( _iguana_spendvectorconv(vec,&spentU[vec->unspentind],numpkinds,vec->hdrsi,vec->unspentind) != 0 ) + converted++; + else + { + printf("iguana_spendvectorconv.[%d] error [%d] at %d of T[%d/%d] [%d] u%u p%u\n",spentbp->hdrsi,bp->hdrsi,j,bp->numtmpspends,n,vec->hdrsi,vec->unspentind,spentU[vec->unspentind].pkind); + return(-1); + } + } + } + } + } + else if ( bp->hdrsi < coin->bundlescount-1 ) + { + //printf("iguana_spendvectorconvs: [%d] null bp.%p\n",i,bp); + } + } + spentbp->converted = (uint32_t)time(NULL); + //printf("spendvectorconvs.[%d] converted.%d\n",refbp->hdrsi,converted); + return(converted); +} + +int32_t iguana_convert(struct iguana_info *coin,int32_t helperid,struct iguana_bundle *bp,int32_t RTflag,int32_t starti) +{ + static int64_t total[256],depth; + int32_t i,n,m,max,converted; int64_t total_tmpspends,sum; double startmillis = OS_milliseconds(); + depth++; + if ( (converted= iguana_spendvectorconvs(coin,bp,starti)) < 0 ) + { + printf("error iguana_convert.[%d]\n",bp->hdrsi); + return(0); + } + else + { + n = coin->bundlescount; + for (i=m=total_tmpspends=0; ibundles[i] != 0 ) + { + total_tmpspends += coin->bundles[i]->numtmpspends; + if ( coin->bundles[i]->converted > 1 ) + m++; + } + } + max = (int32_t)(sizeof(total) / sizeof(*total)); + total[helperid % max] += converted; + for (i=sum=0; ihdrsi,OS_milliseconds()-startmillis,converted,m,n,(long long)sum,(long long)total_tmpspends,(int32_t)depth); + } + depth--; + return(converted); +} + +int32_t iguana_bundlevalidate(struct iguana_info *coin,struct iguana_bundle *bp,int32_t forceflag) +{ + static int32_t totalerrs,totalvalidated; + FILE *fp; char fname[1024]; uint8_t *blockspace; uint32_t now = (uint32_t)time(NULL); + int32_t i,max,len,errs = 0; struct sha256_vstate vstate; bits256 validatehash; int64_t total = 0; + if ( (coin->VALIDATENODE == 0 && coin->RELAYNODE == 0) || bp->ramchain.from_ro != 0 || bp == coin->current ) + { + bp->validated = (uint32_t)time(NULL); + return(bp->n); + } + if ( bp->validated <= 1 || forceflag != 0 ) + { + //printf("validate.[%d]\n",bp->hdrsi); + vupdate_sha256(validatehash.bytes,&vstate,0,0); + sprintf(fname,"%s/%s/validated/%d",GLOBAL_DBDIR,coin->symbol,bp->bundleheight); + //printf("validatefname.(%s)\n",fname); + if ( (fp= fopen(fname,"rb")) != 0 ) + { + if ( forceflag == 0 ) + { + if ( fread(&bp->validated,1,sizeof(bp->validated),fp) != sizeof(bp->validated) ||fread(&total,1,sizeof(total),fp) != sizeof(total) || fread(&validatehash,1,sizeof(validatehash),fp) != sizeof(validatehash) ) + { + printf("error reading.(%s)\n",fname); + total = bp->validated = 0; + } //else printf("(%s) total.%d validated.%u\n",fname,(int32_t)total,bp->validated); + } else OS_removefile(fname,1); + fclose(fp); + } + if ( forceflag != 0 || bp->validated <= 1 ) + { + max = sizeof(coin->blockspace); + blockspace = calloc(1,max); + iguana_volatilesmap(coin,&bp->ramchain); + for (i=0; in; i++) + { + if ( (len= iguana_peerblockrequest(coin,blockspace,max,0,bp->hashes[i],1)) < 0 ) + { + errs++; + iguana_blockunmark(coin,bp->blocks[i],bp,i,1); + totalerrs++; + } + else + { + vupdate_sha256(validatehash.bytes,&vstate,bp->hashes[i].bytes,sizeof(bp->hashes[i])); + total += len, totalvalidated++; + } + } + free(blockspace); + bp->validated = (uint32_t)time(NULL); + printf("VALIDATED.[%d] ht.%d duration.%d errs.%d total.%lld %u | total errs.%d validated.%d %llx\n",bp->hdrsi,bp->bundleheight,bp->validated - now,errs,(long long)total,bp->validated,totalerrs,totalvalidated,(long long)validatehash.txid); + } + if ( errs == 0 && fp == 0 ) + { + if ( (fp= fopen(fname,"wb")) != 0 ) + { + if ( fwrite(&bp->validated,1,sizeof(bp->validated),fp) != sizeof(bp->validated) || fwrite(&total,1,sizeof(total),fp) != sizeof(total) || fwrite(&validatehash,1,sizeof(validatehash),fp) != sizeof(validatehash) ) + printf("error saving.(%s) total.%lld\n",fname,(long long)total); + fclose(fp); + } + } + bp->validatehash = validatehash; + } // else printf("skip validate.[%d] validated.%u force.%d\n",bp->hdrsi,bp->validated,forceflag); + if ( errs != 0 ) + { + printf("remove.[%d]\n",bp->hdrsi); + iguana_bundleremove(coin,bp->hdrsi,0); + } + return(bp->n - errs); +} diff --git a/iguana/iguana_txidfind.c b/iguana/iguana_txidfind.c new file mode 100755 index 000000000..7a6b5be2e --- /dev/null +++ b/iguana/iguana_txidfind.c @@ -0,0 +1,609 @@ +/****************************************************************************** + * 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" + +int32_t iguana_alloctxbits(struct iguana_info *coin,struct iguana_ramchain *ramchain) +{ + static int64_t total; + if ( ramchain->txbits == 0 ) + { + int32_t tlen; uint8_t *TXbits = (uint8_t *)((long)ramchain->H.data + ramchain->H.data->TXoffset); + tlen = (int32_t)hconv_bitlen(ramchain->H.data->numtxsparse * ramchain->H.data->txsparsebits); + ramchain->txbits = calloc(1,tlen); + memcpy(ramchain->txbits,TXbits,tlen); + total += tlen; + char str[65]; printf("alloc.[%d] txbits.%p[%d] total %s\n",ramchain->H.data->height/coin->chain->bundlesize,ramchain->txbits,tlen,mbstr(str,total)); + return(tlen); + } + return(-1); +} + +int32_t iguana_alloccacheT(struct iguana_info *coin,struct iguana_ramchain *ramchain) +{ + static int64_t total; + if ( ramchain->cacheT == 0 ) + { + int32_t i,tlen; struct iguana_txid *T = (void *)((long)ramchain->H.data + ramchain->H.data->Toffset); + tlen = sizeof(*T) * ramchain->H.data->numtxids; + if ( (ramchain->cacheT= calloc(1,tlen)) != 0 ) + { + //memcpy(ramchain->cacheT,T,tlen); + for (i=0; iH.data->numtxids; i++) + ramchain->cacheT[i] = T[i]; + } else ramchain->cacheT = T; + total += tlen; + char str[65]; printf("alloc.[%d] cacheT.%p[%d] total %s\n",ramchain->H.data->height/coin->chain->bundlesize,ramchain->cacheT,tlen,mbstr(str,total)); + return(tlen); + } + return(-1); +} + +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,struct iguana_ramchain *ramchain,uint32_t maxitems) +{ + 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; uint32_t *table,retval = 0; + 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); + } + //if ( setind == 0 ) + // ramchain->sparsesearches++; + //else ramchain->sparseadds++; + if ( 0 && (ramchain->sparsesearches % 1000000) == 0 ) + printf("[%3d] %7d.[%-2d %8d] %5.3f adds.(%-10ld %10ld) search.(hits.%-10ld %10ld) %5.2f%% max.%ld\n",ramchain->height/ramchain->H.data->numblocks,ramchain->height,width,tablesize,(double)(ramchain->sparseadditers + ramchain->sparsesearchiters)/(1+ramchain->sparsesearches+ramchain->sparseadds),ramchain->sparseadds,ramchain->sparseadditers,ramchain->sparsehits,ramchain->sparsesearches,100.*(double)ramchain->sparsehits/(1+ramchain->sparsesearches),ramchain->sparsemax+1); + if ( width == 32 ) + { + table = (uint32_t *)bits; + for (i=0; i= tablesize ) + ind = 0; + if ( (x= table[ind]) == 0 ) + { + //if ( ++i > ramchain->sparsemax ) + // ramchain->sparsemax = i; + if ( (retval= setind) != 0 ) + { + //ramchain->sparseadditers += i; + table[ind] = setind; + } //else ramchain->sparsesearchiters += i; + return(setind); + } + else if ( x < maxitems && memcmp((void *)(long)((long)refdata + x*refsize),key,keylen) == 0 ) + { + if ( setind != 0 && setind != x ) + printf("sparseadd index collision setind.%d != x.%d refsize.%d keylen.%d\n",setind,x,refsize,keylen); + //ramchain->sparsehits++; + //if ( ++i > ramchain->sparsemax ) + // ramchain->sparsemax = i; + //ramchain->sparseadditers += i; + return(x); + } + } + } + else + { + bitoffset = (ind * width); + 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; + } + x = 0; + if ( width == 32 ) + memcpy(&x,&bits[bitoffset >> 3],4); + else if ( width == 16 ) + memcpy(&x,&bits[bitoffset >> 3],2); + else if ( width != 8 ) + { + 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; + } + } + else x = bits[bitoffset >> 3]; + if ( 0 && setind == 0 ) + printf("x.%d\n",x); + if ( x == 0 ) + { + if ( (x= setind) == 0 ) + { + //ramchain->sparsesearchiters += (i+1); + return(0); + } + //else ramchain->sparseadditers += (i+1); + if ( width == 32 ) + memcpy(&bits[bitoffset >> 3],&setind,4); + else if ( width == 16 ) + memcpy(&bits[bitoffset >> 3],&setind,2); + else if ( width != 8 ) + { + 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]; + } + } + else bits[bitoffset >> 3] = setind; + if ( 0 ) + { + for (x=j=0; j ramchain->sparsemax ) + // ramchain->sparsemax = i; + return(setind); + } + else if ( x < maxitems && memcmp((void *)(long)((long)refdata + x*refsize),key,keylen) == 0 ) + { + if ( setind == 0 ) + ramchain->sparsehits++; + else if ( setind != x ) + printf("sparseadd index collision setind.%d != x.%d refsize.%d keylen.%d\n",setind,x,refsize,keylen); + if ( i > ramchain->sparsemax ) + ramchain->sparsemax = i; + 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,struct iguana_ramchain *ramchain) +{ + uint32_t ind,retval; + //char str[65]; printf("sparseaddtx %s txidind.%d bits.%p\n",bits256_str(str,txid),txidind,bits); + ind = (txid.ulongs[0] ^ txid.ulongs[1] ^ txid.ulongs[2] ^ txid.ulongs[3]) % tablesize; + if ( (retval= iguana_sparseadd(bits,ind,width,tablesize,txid.bytes,sizeof(txid),txidind,T,sizeof(*T),ramchain,ramchain->H.data->numtxids)) != 0 ) + { + char str[65]; + if ( txidind != 0 && retval != txidind ) + printf("sparse tx collision %s %u vs %u\n",bits256_str(str,txid),retval,txidind); + return(retval); + } + return(retval); +} + +uint32_t iguana_sparseaddpk(uint8_t *bits,int32_t width,uint32_t tablesize,uint8_t rmd160[20],struct iguana_pkhash *P,uint32_t pkind,struct iguana_ramchain *ramchain) +{ + uint32_t ind,key2; uint64_t key0,key1; + //int32_t i; for (i=0; i<20; i++) + // printf("%02x",rmd160[i]); + //char str[65]; printf(" sparseaddpk pkind.%d bits.%p\n",pkind,bits); + 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),ramchain,ramchain->H.data->numpkinds)); +} + +int32_t iguana_ramchain_spendtxid(struct iguana_info *coin,uint32_t *unspentindp,bits256 *txidp,struct iguana_txid *T,int32_t numtxids,bits256 *X,int32_t numexternaltxids,struct iguana_spend *s) +{ + uint32_t ind,external; + *unspentindp = 0; + memset(txidp,0,sizeof(*txidp)); + ind = s->spendtxidind; + external = (ind >> 31) & 1; + ind &= ~(1 << 31); + //printf("s.%p ramchaintxid vout.%x spendtxidind.%d isext.%d ext.%d ind.%d\n",s,s->prevout,ind,s->external,external,ind); + if ( s->prevout < 0 ) + return(-1); + if ( s->external != 0 && s->external == external && ind < numexternaltxids ) + { + //printf("ind.%d X.%p[%d]\n",ind,X,numexternaltxids); + *txidp = X[ind]; + return(s->prevout); + } + else if ( s->external == 0 && s->external == external && ind < numtxids ) + { + *txidp = T[ind].txid; + *unspentindp = T[ind].firstvout + s->prevout; + return(s->prevout); + } + return(-2); +} + +struct iguana_txid *iguana_txidfind(struct iguana_info *coin,int32_t *heightp,struct iguana_txid *tx,bits256 txid,int32_t lasthdrsi) +{ + uint8_t *TXbits; struct iguana_txid *T; uint32_t txidind; int32_t i; + struct iguana_bundle *bp; struct iguana_ramchain *ramchain; //struct iguana_block *block; + *heightp = -1; + if ( lasthdrsi < 0 ) + return(0); + for (i=lasthdrsi; i>=0; i--) + { + if ( (bp= coin->bundles[i]) != 0 && (bp == coin->current || bp->emitfinish > 1) ) + { + ramchain = (bp == coin->current) ? &coin->RTramchain : &bp->ramchain; + if ( ramchain->H.data != 0 ) + { + if ( (TXbits= ramchain->txbits) == 0 ) + { + if ( coin->fastfind == 0 && bp != coin->current ) + iguana_alloctxbits(coin,ramchain); + if ( (TXbits= ramchain->txbits) == 0 ) + { + //printf("use memory mapped.[%d]\n",ramchain->H.data->height/coin->chain->bundlesize); + TXbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->TXoffset); + } + } + if ( (T= ramchain->cacheT) == 0 ) + { + //if ( coin->fastfind == 0 ) + // iguana_alloccacheT(coin,ramchain); + //if ( (T= ramchain->cacheT) == 0 ) + T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); + } + if ( (txidind= iguana_sparseaddtx(TXbits,ramchain->H.data->txsparsebits,ramchain->H.data->numtxsparse,txid,T,0,ramchain)) > 0 ) + { + //printf("found txidind.%d\n",txidind); + if ( bits256_cmp(txid,T[txidind].txid) == 0 ) + { + if ( 0 ) + { + int32_t j; struct iguana_block *block; + for (j=0; jn; j++) + if ( (block= bp->blocks[j]) != 0 && txidind >= block->RO.firsttxidind && txidind < block->RO.firsttxidind+block->RO.txn_count ) + break; + if ( j < bp->n ) + { + if ( j != T[txidind].bundlei ) + printf("bundlei mismatch j.%d != %d\n",j,T[txidind].bundlei); + else + { + *heightp = bp->bundleheight + T[txidind].bundlei; + //printf("found height.%d\n",*heightp); + *tx = T[txidind]; + return(tx); + } + } + } + else + { + *heightp = bp->bundleheight + T[txidind].bundlei; + //printf("found height.%d\n",*heightp); + *tx = T[txidind]; + return(tx); + } + } + char str[65],str2[65]; printf("iguana_txidfind mismatch.[%d:%d] %d %s vs %s\n",bp->hdrsi,T[txidind].extraoffset,txidind,bits256_str(str,txid),bits256_str(str2,T[txidind].txid)); + return(0); + } + } + } + } + return(0); +} + +int32_t iguana_txidfastfind(struct iguana_info *coin,int32_t *heightp,bits256 txid,int32_t lasthdrsi) +{ + uint8_t *sorted,*item; int32_t i,j,val,num,tablesize,*hashtable; uint32_t firstvout; + if ( (sorted= coin->fast[txid.bytes[31]]) != 0 ) + { + memcpy(&num,sorted,sizeof(num)); + memcpy(&tablesize,&sorted[sizeof(num)],sizeof(tablesize)); + if ( (hashtable= coin->fasttables[txid.bytes[31]]) == 0 ) + { + hashtable = (int32_t *)((long)sorted + (1 + num)*16); + //printf("backup hashtable\n"); + } + val = (txid.uints[4] % tablesize); + for (j=0; j= tablesize ) + val = 0; + if ( (i= hashtable[val]) == 0 ) + return(-1); + else + { + if ( i > num ) + { + printf("illegal val.%d vs num.%d tablesize.%d fastfind.%02x\n",i,num,tablesize,txid.bytes[31]); + return(-1); + } + else + { + item = (void *)((long)sorted + i*16); + if ( memcmp(&txid.txid,item,sizeof(uint64_t)) == 0 ) + { + memcpy(&firstvout,&item[sizeof(uint64_t)],sizeof(firstvout)); + memcpy(heightp,&item[sizeof(uint64_t) + sizeof(firstvout)],sizeof(*heightp)); + //printf("i.%d val.%d height.%d firstvout.%d j.%d\n",i,val,*heightp,firstvout,j); + if ( *heightp >= (lasthdrsi+1)*coin->chain->bundlesize ) + { + printf("txidfastfind: unexpected height.%d with lasthdrsi.%d\n",*heightp,lasthdrsi); + return(-1); + } + return(firstvout); + } + else if ( 0 ) + { + int32_t k; + for (k=-16; k<0; k++) + printf("%02x ",item[k]); + printf("<"); + for (k=0; k<16; k++) + printf("%02x ",item[k]); + printf(">"); + for (k=16; k<32; k++) + printf("%02x ",item[k]); + printf("\n"); + printf("txid.%llx vs item.%llx ht.%d 1st.%d\n",(long long)txid.txid,*(long long *)item,*(int32_t *)&item[sizeof(uint64_t)],*(int32_t *)&item[sizeof(uint64_t)+sizeof(uint32_t)]); + } + } + } + } + } + return(-1); +} + +int32_t iguana_unspentindfind(struct iguana_info *coin,int32_t *heightp,bits256 txid,int32_t vout,int32_t lasthdrsi) +{ + struct iguana_txid *tp,TX; int32_t firstvout; + if ( coin->fastfind != 0 && (firstvout= iguana_txidfastfind(coin,heightp,txid,lasthdrsi)) >= 0 ) + { + return(firstvout + vout); + } + if ( (tp= iguana_txidfind(coin,heightp,&TX,txid,lasthdrsi)) != 0 ) + return(tp->firstvout + vout); + return(-1); +} + +int32_t iguana_fastfindadd(struct iguana_info *coin,bits256 txid,int32_t height,uint32_t firstvout) +{ + FILE *fp; + if ( bits256_nonz(txid) != 0 && (fp= coin->fastfps[txid.bytes[31]]) != 0 ) + { + txid.uints[6] = firstvout; + txid.uints[7] = height; + if ( fwrite(&txid,1,sizeof(txid),fp) == sizeof(txid) ) + return(1); + } + return(0); +} + +int64_t iguana_fastfindinitbundle(struct iguana_info *coin,struct iguana_bundle *bp,int32_t iter) +{ + int32_t i; struct iguana_txid *T; struct iguana_ramchaindata *rdata; int64_t n = 0; + if ( (rdata= bp->ramchain.H.data) != 0 ) + { + T = (void *)(long)((long)rdata + rdata->Toffset); + n = rdata->numtxids; + if ( iter == 1 ) + { + for (i=0; ibundleheight + T[i].bundlei,T[i].firstvout); + fprintf(stderr,"[%d:%u] ",bp->hdrsi,(int32_t)n); + } + } + return(n); +} + +static int _bignum_cmp(const void *a,const void *b) +{ + uint8_t *biga,*bigb; int32_t i,diff; + biga = (uint8_t *)a; + bigb = (uint8_t *)b; + for (i=0; i<32; i++) + { + if ( (diff= (biga[i] - bigb[i])) > 0 ) + return(1); + else if ( diff < 0 ) + return(-1); + } + return(0); +} + +uint32_t iguana_fastfindinit(struct iguana_info *coin) +{ + int32_t i,j,iter,num,tablesize,*hashtable; uint8_t *sorted; char fname[1024]; + //if ( strcmp("BTC",coin->symbol) != 0 ) + // return(0); + if ( coin->fastfind != 0 ) + return(coin->fastfind); + for (iter=0; iter<2; iter++) + { + for (i=0; i<0x100; i++) + { + sprintf(fname,"DB/%s%s/fastfind/%02x.all",iter!=0?"ro/":"",coin->symbol,i), OS_compatible_path(fname); + if ( (coin->fast[i]= OS_mapfile(fname,&coin->fastsizes[i],0)) == 0 ) + break; + else + { + fprintf(stderr,"."); + sorted = coin->fast[i]; + if ( 0 ) + { + coin->fast[i] = calloc(1,coin->fastsizes[i]); + memcpy(coin->fast[i],sorted,coin->fastsizes[i]); + munmap(sorted,coin->fastsizes[i]); + } + sorted = coin->fast[i]; + memcpy(&num,sorted,sizeof(num)); + memcpy(&tablesize,&sorted[sizeof(num)],sizeof(tablesize)); + if ( (num+1)*16 + tablesize*sizeof(*hashtable) == coin->fastsizes[i] ) + { + hashtable = (int32_t *)((long)sorted + (1 + num)*16); + if ( 0 ) + { + coin->fasttables[i] = calloc(tablesize,sizeof(*hashtable)); + memcpy(coin->fasttables[i],hashtable,tablesize * sizeof(*hashtable)); + } + } + else + { + printf("size error num.%d tablesize.%d -> %lu vs %ld\n",num,tablesize,(num+1)*16 + tablesize*sizeof(*hashtable),coin->fastsizes[i]); + break; + } + } + } + if ( i == 0x100 ) + { + coin->fastfind = (uint32_t)time(NULL); + printf("initialized fastfind.%s iter.%d\n",coin->symbol,iter); + return(coin->fastfind); + } + else + { + for (j=0; jfast[i],coin->fastsizes[i]); + free(coin->fasttables[i]); + coin->fast[i] = 0; + coin->fastsizes[i] = 0; + } + } + } + return(0); +} + +int64_t iguana_fastfindcreate(struct iguana_info *coin) +{ + int32_t i,j,val,iter,errs,num,ind,tablesize,*hashtable; bits256 *sortbuf,hash2; long allocsize; struct iguana_bundle *bp; char fname[512]; uint8_t buf[16]; int64_t total = 0; + if ( coin->current != 0 && coin->bundlescount == coin->current->hdrsi+1 ) + { + sprintf(fname,"DB/%s/fastfind",coin->symbol), OS_ensure_directory(fname); + for (i=0; i<0x100; i++) + { + sprintf(fname,"DB/%s/fastfind/%02x",coin->symbol,i), OS_compatible_path(fname); + if ( (coin->fastfps[i]= fopen(fname,"wb")) == 0 ) + break; + } + if ( i == 0x100 ) + { + for (iter=0; iter<2; iter++) + { + total = 0; + for (i=0; ibundlescount-1; i++) + if ( (bp= coin->bundles[i]) != 0 ) + total += iguana_fastfindinitbundle(coin,bp,iter); + printf("iguana_fastfindinit iter.%d total.%lld\n",iter,(long long)total); + } + for (i=errs=0; i<0x100; i++) + { + fclose(coin->fastfps[i]); + sprintf(fname,"DB/%s/fastfind/%02x",coin->symbol,i), OS_compatible_path(fname); + //printf("%s\n",fname); + if ( (sortbuf= OS_filestr(&allocsize,fname)) != 0 ) + { + OS_removefile(fname,0); + num = (int32_t)allocsize/sizeof(bits256); + qsort(sortbuf,num,sizeof(bits256),_bignum_cmp); + strcat(fname,".all"); + if ( (coin->fastfps[i]= fopen(fname,"wb")) != 0 ) + { + tablesize = (num << 1); + hashtable = calloc(sizeof(*hashtable),tablesize); + for (ind=1; ind<=num; ind++) + { + hash2 = sortbuf[ind-1]; + val = (hash2.uints[4] % tablesize); + for (j=0; j= tablesize ) + val = 0; + if ( hashtable[val] == 0 ) + { + hashtable[val] = ind; + break; + } + } + } + memset(&hash2,0,sizeof(hash2)); + hash2.uints[0] = num; + hash2.uints[1] = tablesize; + for (j=0; j<=num; j++) + { + memcpy(buf,&hash2.txid,sizeof(hash2.txid)); + memcpy(&buf[sizeof(hash2.txid)],&hash2.uints[6],sizeof(hash2.uints[6])); + memcpy(&buf[sizeof(hash2.txid) + sizeof(hash2.uints[6])],&hash2.uints[7],sizeof(hash2.uints[7])); + fwrite(buf,1,sizeof(buf),coin->fastfps[i]); + //fwrite(hash2,1,sizeof(hash2),coin->fastfps[i]); + if ( j < num ) + { + hash2 = sortbuf[j]; + //char str[65]; printf("%d %s\n",j,bits256_str(str,hash2)); + } + } + if ( fwrite(hashtable,sizeof(*hashtable),tablesize,coin->fastfps[i]) == tablesize ) + { + fclose(coin->fastfps[i]); + coin->fastfps[i] = 0; + if ( (coin->fast[i]= OS_mapfile(fname,&coin->fastsizes[i],0)) != 0 ) + { + } else errs++; + printf("%s fastfind.[%02x] num.%d tablesize.%d errs.%d %p[%ld]\n",fname,i,num,tablesize,errs,coin->fast[i],coin->fastsizes[i]); + } + else + { + printf("error saving (%s)\n",fname); + OS_removefile(fname,0); + fclose(coin->fastfps[i]); + coin->fastfps[i] = 0; + } + free(hashtable); + } else printf("couldnt overwrite (%s)\n",fname); + free(sortbuf); + } else printf("couldnt load sortbuf (%s)\n",fname); + } + printf("initialized with errs.%d\n",errs); + if ( errs == 0 ) + coin->fastfind = (uint32_t)time(NULL); + } + } + return(total); +} diff --git a/iguana/iguana_unspents.c b/iguana/iguana_unspents.c index a66f42247..fa59d8a00 100755 --- a/iguana/iguana_unspents.c +++ b/iguana/iguana_unspents.c @@ -20,2682 +20,327 @@ #include "iguana777.h" #include "exchanges/bitcoin.h" -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); -} - -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) -{ - //static struct iguana_hhutxo *HHUTXO; static struct iguana_hhaccount *HHACCT; static uint32_t numHHUTXO,maxHHUTXO,numHHACCT,maxHHACCT; - 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) - { - //HASH_DEL(coin->utxotable,hhutxo); - hhutxo->u.spentflag = 0; - hhutxo->u.fromheight = 0; - hhutxo->u.prevunspentind = 0; - //free(hhutxo); - } - //coin->utxotable = 0; - } - if ( coin->accountstable != 0 ) - { - HASH_ITER(hh,coin->accountstable,hhacct,tmpacct) - { - //HASH_DEL(coin->accountstable,hhacct); - hhacct->a.lastunspentind = 0; - hhacct->a.total = 0; - //free(hhacct); - } - //coin->accountstable = 0; - } - /*if ( HHUTXO != 0 ) - { - free(HHUTXO); - maxHHUTXO = numHHUTXO = 0; - HHUTXO = 0; - } - if ( HHACCT != 0 ) - { - free(HHACCT); - maxHHACCT = numHHACCT = 0; - HHACCT = 0; - }*/ - 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 && hhutxo->u.spentflag != 0 ) - { - printf("hhutxo.%p spentflag.%d\n",hhutxo,hhutxo->u.spentflag); - return(-1); - } - /*if ( 0 && numHHUTXO+1 >= maxHHUTXO ) - { - maxHHUTXO += 1; - HHUTXO = realloc(HHUTXO,sizeof(*HHUTXO) * maxHHUTXO); - }*/ - hhutxo = calloc(1,sizeof(*hhutxo));//&HHUTXO[numHHUTXO++], memset(hhutxo,0,sizeof(*hhutxo)); - hhutxo->uval = uval; - HASH_ADD_KEYPTR(hh,coin->utxotable,&hhutxo->uval,sizeof(hhutxo->uval),hhutxo); - if ( (hhacct= iguana_hhaccountfind(coin,pval)) == 0 ) - { - /*if ( 0 && numHHACCT+1 >= maxHHACCT ) - { - maxHHACCT += 1; - HHACCT = realloc(HHACCT,sizeof(*HHACCT) * maxHHACCT); - }*/ - hhacct = calloc(1,sizeof(*hhacct)); // &HHACCT[numHHACCT++], memset(hhacct,0,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.fromheight = fromheight; - hhutxo->u.prevunspentind = hhacct->a.lastunspentind; - hhacct->a.lastunspentind = spent_unspentind; - hhacct->a.total += spent_value; - /*if ( iguana_hhutxofind(coin,uval) == 0 || iguana_hhaccountfind(coin,pval) == 0 ) - { - printf("null hh find.(%ld %ld) %p %p\n",(long)uval,(long)pval,iguana_hhutxofind(coin,uval),iguana_hhaccountfind(coin,pval)); - }*/ - return(0); -} - -int32_t iguana_alloctxbits(struct iguana_info *coin,struct iguana_ramchain *ramchain) -{ - static int64_t total; - if ( ramchain->txbits == 0 ) - { - int32_t tlen; uint8_t *TXbits = (uint8_t *)((long)ramchain->H.data + ramchain->H.data->TXoffset); - tlen = (int32_t)hconv_bitlen(ramchain->H.data->numtxsparse * ramchain->H.data->txsparsebits); - ramchain->txbits = calloc(1,tlen); - memcpy(ramchain->txbits,TXbits,tlen); - total += tlen; - char str[65]; printf("alloc.[%d] txbits.%p[%d] total %s\n",ramchain->H.data->height/coin->chain->bundlesize,ramchain->txbits,tlen,mbstr(str,total)); - return(tlen); - } - return(-1); -} - -int32_t iguana_alloccacheT(struct iguana_info *coin,struct iguana_ramchain *ramchain) -{ - static int64_t total; - if ( ramchain->cacheT == 0 ) - { - int32_t i,tlen; struct iguana_txid *T = (void *)((long)ramchain->H.data + ramchain->H.data->Toffset); - tlen = sizeof(*T) * ramchain->H.data->numtxids; - if ( (ramchain->cacheT= calloc(1,tlen)) != 0 ) - { - //memcpy(ramchain->cacheT,T,tlen); - for (i=0; iH.data->numtxids; i++) - ramchain->cacheT[i] = T[i]; - } else ramchain->cacheT = T; - total += tlen; - char str[65]; printf("alloc.[%d] cacheT.%p[%d] total %s\n",ramchain->H.data->height/coin->chain->bundlesize,ramchain->cacheT,tlen,mbstr(str,total)); - return(tlen); - } - 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 != %ld\n",ramchain->debitsfilesize,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 != %ld\n",ramchain->lastspendsfilesize,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 && ramchain->A2 != ramchain->debitsfileptr+sizeof(bits256)*2+sizeof(int32_t) ) - free(ramchain->A2); - if ( ramchain->allocatedU2 != 0 && ramchain->Uextras != 0 && ramchain->Uextras != 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 ) - 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) * ramchain->H.data->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 && 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) * ramchain->H.data->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 && 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); - //printf("volatilesmap.[%d] %p %p\n",ramchain->height/coin->chain->bundlesize,ramchain->debitsfileptr,ramchain->lastspendsfileptr); - err = 0; - } 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 - { - printf("ramchain.[%d] map error balanceswritten %d vs %d hashes %x %x\n",ramchain->H.data->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); -} - -int32_t iguana_spentflag(struct iguana_info *coin,int64_t *RTspendp,int32_t *spentheightp,struct iguana_ramchain *ramchain,int16_t spent_hdrsi,uint32_t spent_unspentind,int32_t height,int32_t minconf,int32_t maxconf,uint64_t amount) -{ - uint32_t numunspents; struct iguana_hhutxo *hhutxo; struct iguana_utxo utxo; uint64_t confs,val,RTspend = 0; - *spentheightp = 0; - numunspents = ramchain->H.data->numunspents; - memset(&utxo,0,sizeof(utxo)); - val = ((uint64_t)spent_hdrsi << 32) | spent_unspentind; - if ( spent_unspentind != 0 && spent_unspentind < numunspents ) - { - if ( ramchain->Uextras != 0 ) - utxo = ramchain->Uextras[spent_unspentind]; - if ( ramchain->Uextras == 0 || utxo.spentflag == 0 ) - { - //printf("check hhutxo [%d] u%u %p\n",spent_hdrsi,spent_unspentind,iguana_hhutxofind(coin,((uint64_t)202<<32)|3909240)); - if ( (hhutxo= iguana_hhutxofind(coin,val)) != 0 ) - { - utxo = hhutxo->u; - if ( utxo.spentflag != 0 ) - RTspend = amount; - } - } - } - else - { - printf("illegal unspentind.%u vs %u hdrs.%d\n",spent_unspentind,numunspents,spent_hdrsi); - return(-1); - } - if ( utxo.spentflag != 0 && utxo.fromheight == 0 ) - { - printf("illegal unspentind.%u vs %u hdrs.%d zero fromheight?\n",spent_unspentind,numunspents,spent_hdrsi); - return(-1); - } - //printf("[%d] u%u %.8f, spentheight.%d vs height.%d spentflag.%d\n",spent_hdrsi,spent_unspentind,dstr(amount),utxo.fromheight,height,utxo.spentflag); - *spentheightp = utxo.fromheight; - if ( (confs= coin->blocks.hwmchain.height - utxo.fromheight) >= minconf && confs < maxconf && (height == 0 || utxo.fromheight < height) ) - { - (*RTspendp) += RTspend; - return(utxo.spentflag); - } - 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_account *A2; struct iguana_ramchaindata *rdata; struct iguana_utxo *utxo; - if ( (rdata= spentchain->H.data) != 0 ) - { - if ( incremental == 0 ) - { - if ( spentchain->Uextras == 0 || spentchain->A2 == 0 ) - iguana_volatilesmap(coin,spentchain); - 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->spentflag = 1; - utxo->fromheight = fromheight; - A2[spent_pkind].total += spent_value; - A2[spent_pkind].lastunspentind = spent_unspentind; - return(0); - } - else - { - 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 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; - if ( iguana_utxoupdate(coin,spent_hdrsi,spent_unspentind,spent_pkind,spent_value,spendind,fromheight) == 0 ) - { - /*totalmillis += (OS_milliseconds() - startmillis); - if ( (++utxon % 100000) == 0 ) - printf("ave utxo[%d] %.2f micros total %.2f seconds\n",utxon,(1000. * totalmillis)/utxon,totalmillis/1000.);*/ - return(0); - } - } - printf("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); - if ( coin->current != 0 && fromheight >= coin->current->bundleheight ) - coin->RTdatabad = 1; - else - { - printf("from.%d vs current.%d\n",fromheight,coin->current->bundleheight); - iguana_bundleremove(coin,spent_hdrsi,0); - iguana_bundleremove(coin,fromheight/coin->chain->bundlesize,0); - } - exit(-1); - } else printf("volatileupdate error null rdata [%d]\n",spentchain->height/coin->current->bundleheight); - return(-1); -} - -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,struct iguana_ramchain *ramchain,uint32_t maxitems) -{ - 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; uint32_t *table,retval = 0; - 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); - } - //if ( setind == 0 ) - // ramchain->sparsesearches++; - //else ramchain->sparseadds++; - if ( 0 && (ramchain->sparsesearches % 1000000) == 0 ) - printf("[%3d] %7d.[%-2d %8d] %5.3f adds.(%-10ld %10ld) search.(hits.%-10ld %10ld) %5.2f%% max.%ld\n",ramchain->height/ramchain->H.data->numblocks,ramchain->height,width,tablesize,(double)(ramchain->sparseadditers + ramchain->sparsesearchiters)/(1+ramchain->sparsesearches+ramchain->sparseadds),ramchain->sparseadds,ramchain->sparseadditers,ramchain->sparsehits,ramchain->sparsesearches,100.*(double)ramchain->sparsehits/(1+ramchain->sparsesearches),ramchain->sparsemax+1); - if ( width == 32 ) - { - table = (uint32_t *)bits; - for (i=0; i= tablesize ) - ind = 0; - if ( (x= table[ind]) == 0 ) - { - //if ( ++i > ramchain->sparsemax ) - // ramchain->sparsemax = i; - if ( (retval= setind) != 0 ) - { - //ramchain->sparseadditers += i; - table[ind] = setind; - } //else ramchain->sparsesearchiters += i; - return(setind); - } - else if ( x < maxitems && memcmp((void *)(long)((long)refdata + x*refsize),key,keylen) == 0 ) - { - if ( setind != 0 && setind != x ) - printf("sparseadd index collision setind.%d != x.%d refsize.%d keylen.%d\n",setind,x,refsize,keylen); - //ramchain->sparsehits++; - //if ( ++i > ramchain->sparsemax ) - // ramchain->sparsemax = i; - //ramchain->sparseadditers += i; - return(x); - } - } - } - else - { - bitoffset = (ind * width); - 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; - } - x = 0; - if ( width == 32 ) - memcpy(&x,&bits[bitoffset >> 3],4); - else if ( width == 16 ) - memcpy(&x,&bits[bitoffset >> 3],2); - else if ( width != 8 ) - { - 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; - } - } - else x = bits[bitoffset >> 3]; - if ( 0 && setind == 0 ) - printf("x.%d\n",x); - if ( x == 0 ) - { - if ( (x= setind) == 0 ) - { - //ramchain->sparsesearchiters += (i+1); - return(0); - } - //else ramchain->sparseadditers += (i+1); - if ( width == 32 ) - memcpy(&bits[bitoffset >> 3],&setind,4); - else if ( width == 16 ) - memcpy(&bits[bitoffset >> 3],&setind,2); - else if ( width != 8 ) - { - 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]; - } - } - else bits[bitoffset >> 3] = setind; - if ( 0 ) - { - for (x=j=0; j ramchain->sparsemax ) - // ramchain->sparsemax = i; - return(setind); - } - else if ( x < maxitems && memcmp((void *)(long)((long)refdata + x*refsize),key,keylen) == 0 ) - { - if ( setind == 0 ) - ramchain->sparsehits++; - else if ( setind != x ) - printf("sparseadd index collision setind.%d != x.%d refsize.%d keylen.%d\n",setind,x,refsize,keylen); - if ( i > ramchain->sparsemax ) - ramchain->sparsemax = i; - 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,struct iguana_ramchain *ramchain) -{ - uint32_t ind,retval; - //char str[65]; printf("sparseaddtx %s txidind.%d bits.%p\n",bits256_str(str,txid),txidind,bits); - ind = (txid.ulongs[0] ^ txid.ulongs[1] ^ txid.ulongs[2] ^ txid.ulongs[3]) % tablesize; - if ( (retval= iguana_sparseadd(bits,ind,width,tablesize,txid.bytes,sizeof(txid),txidind,T,sizeof(*T),ramchain,ramchain->H.data->numtxids)) != 0 ) - { - char str[65]; - if ( txidind != 0 && retval != txidind ) - printf("sparse tx collision %s %u vs %u\n",bits256_str(str,txid),retval,txidind); - return(retval); - } - return(retval); -} - -uint32_t iguana_sparseaddpk(uint8_t *bits,int32_t width,uint32_t tablesize,uint8_t rmd160[20],struct iguana_pkhash *P,uint32_t pkind,struct iguana_ramchain *ramchain) -{ - uint32_t ind,key2; uint64_t key0,key1; - //int32_t i; for (i=0; i<20; i++) - // printf("%02x",rmd160[i]); - //char str[65]; printf(" sparseaddpk pkind.%d bits.%p\n",pkind,bits); - 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),ramchain,ramchain->H.data->numpkinds)); -} - -int32_t iguana_ramchain_spendtxid(struct iguana_info *coin,uint32_t *unspentindp,bits256 *txidp,struct iguana_txid *T,int32_t numtxids,bits256 *X,int32_t numexternaltxids,struct iguana_spend *s) -{ - uint32_t ind,external; - *unspentindp = 0; - memset(txidp,0,sizeof(*txidp)); - ind = s->spendtxidind; - external = (ind >> 31) & 1; - ind &= ~(1 << 31); - //printf("s.%p ramchaintxid vout.%x spendtxidind.%d isext.%d ext.%d ind.%d\n",s,s->prevout,ind,s->external,external,ind); - if ( s->prevout < 0 ) - return(-1); - if ( s->external != 0 && s->external == external && ind < numexternaltxids ) - { - //printf("ind.%d X.%p[%d]\n",ind,X,numexternaltxids); - *txidp = X[ind]; - return(s->prevout); - } - else if ( s->external == 0 && s->external == external && ind < numtxids ) - { - *txidp = T[ind].txid; - *unspentindp = T[ind].firstvout + s->prevout; - return(s->prevout); - } - return(-2); -} - -struct iguana_txid *iguana_txidfind(struct iguana_info *coin,int32_t *heightp,struct iguana_txid *tx,bits256 txid,int32_t lasthdrsi) -{ - uint8_t *TXbits; struct iguana_txid *T; uint32_t txidind; int32_t i; - struct iguana_bundle *bp; struct iguana_ramchain *ramchain; //struct iguana_block *block; - *heightp = -1; - if ( lasthdrsi < 0 ) - return(0); - for (i=lasthdrsi; i>=0; i--) - { - if ( (bp= coin->bundles[i]) != 0 && (bp == coin->current || bp->emitfinish > 1) ) - { - ramchain = (bp == coin->current) ? &coin->RTramchain : &bp->ramchain; - if ( ramchain->H.data != 0 ) - { - if ( (TXbits= ramchain->txbits) == 0 ) - { - if ( coin->fastfind == 0 && bp != coin->current ) - iguana_alloctxbits(coin,ramchain); - if ( (TXbits= ramchain->txbits) == 0 ) - { - //printf("use memory mapped.[%d]\n",ramchain->H.data->height/coin->chain->bundlesize); - TXbits = (void *)(long)((long)ramchain->H.data + ramchain->H.data->TXoffset); - } - } - if ( (T= ramchain->cacheT) == 0 ) - { - //if ( coin->fastfind == 0 ) - // iguana_alloccacheT(coin,ramchain); - //if ( (T= ramchain->cacheT) == 0 ) - T = (void *)(long)((long)ramchain->H.data + ramchain->H.data->Toffset); - } - if ( (txidind= iguana_sparseaddtx(TXbits,ramchain->H.data->txsparsebits,ramchain->H.data->numtxsparse,txid,T,0,ramchain)) > 0 ) - { - //printf("found txidind.%d\n",txidind); - if ( bits256_cmp(txid,T[txidind].txid) == 0 ) - { - if ( 0 ) - { - int32_t j; struct iguana_block *block; - for (j=0; jn; j++) - if ( (block= bp->blocks[j]) != 0 && txidind >= block->RO.firsttxidind && txidind < block->RO.firsttxidind+block->RO.txn_count ) - break; - if ( j < bp->n ) - { - if ( j != T[txidind].bundlei ) - printf("bundlei mismatch j.%d != %d\n",j,T[txidind].bundlei); - else - { - *heightp = bp->bundleheight + T[txidind].bundlei; - //printf("found height.%d\n",*heightp); - *tx = T[txidind]; - return(tx); - } - } - } - else - { - *heightp = bp->bundleheight + T[txidind].bundlei; - //printf("found height.%d\n",*heightp); - *tx = T[txidind]; - return(tx); - } - } - char str[65],str2[65]; printf("iguana_txidfind mismatch.[%d:%d] %d %s vs %s\n",bp->hdrsi,T[txidind].extraoffset,txidind,bits256_str(str,txid),bits256_str(str2,T[txidind].txid)); - return(0); - } - } - } - } - return(0); -} - -struct iguana_bundle *iguana_externalspent(struct iguana_info *coin,bits256 *prevhashp,uint32_t *unspentindp,struct iguana_ramchain *ramchain,int32_t spent_hdrsi,struct iguana_spend *s,int32_t prefetchflag) -{ - 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); - //printf("external X.%p %ld num.%d\n",X,(long)ramchain->H.data->Xoffset,(int32_t)ramchain->H.data->numexternaltxids); - sequenceid = s->sequenceid; - hdrsi = spent_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 ) - { - //double duration,startmillis = OS_milliseconds(); - if ( (tp= iguana_txidfind(coin,&height,&TX,prev_hash,spent_hdrsi-1)) != 0 ) - { - *unspentindp = unspentind = TX.firstvout + ((prev_vout > 0) ? prev_vout : 0); - hdrsi = height / coin->chain->bundlesize; - if ( hdrsi >= 0 && hdrsi < coin->bundlescount && (spentbp= coin->bundles[hdrsi]) != 0 ) - { - //printf("%s height.%d firstvout.%d prev.%d ->U%d\n",bits256_str(str,prev_hash),height,TX.firstvout,prev_vout,unspentind); - /*now = (uint32_t)time(NULL); - duration = (OS_milliseconds() - startmillis); - if ( 0 && ((uint64_t)coin->txidfind_num % 1000000) == 1 ) - printf("%p iguana_txidfind.[%.0f] ave %.2f micros, total %.2f seconds | duration %.3f millis\n",spentbp->ramchain.txbits,coin->txidfind_num,(coin->txidfind_totalmillis*1000.)/coin->txidfind_num,coin->txidfind_totalmillis/1000.,duration); - coin->txidfind_totalmillis += duration; - coin->txidfind_num += 1.;*/ - if ( 1 && coin->PREFETCHLAG > 0 ) - { - if ( spentbp->lastprefetch == 0 ) - { - iguana_ramchain_prefetch(coin,&spentbp->ramchain,prefetchflag); - spentbp->lastprefetch = (uint32_t)time(NULL); - } - /*else if ( 0 && (rand() % IGUANA_NUMHELPERS) == 0 && (duration > 10 || duration > (10 * coin->txidfind_totalmillis)/coin->txidfind_num) ) - { - printf("slow txidfind %.2f vs %.2f prefetch[%d] from.[%d] lag.%ld last.%u\n",duration,coin->txidfind_totalmillis/coin->txidfind_num,spentbp->hdrsi,ramchain->height/coin->chain->bundlesize,time(NULL) - spentbp->lastprefetch,spentbp->lastprefetch); - iguana_ramchain_prefetch(coin,ramchain,1); - //spentbp->lastprefetch = now; - }*/ - } - } - else - { - printf("illegal hdrsi.%d prev_hash.(%s) for bp.[%d]\n",hdrsi,bits256_str(str,prev_hash),spent_hdrsi); - exit(-1); - } - } - else - { - printf("cant find prev_hash.(%s) for bp.[%d]\n",bits256_str(str,prev_hash),spent_hdrsi); - if ( spent_hdrsi < coin->current->hdrsi ) - { - iguana_bundleremove(coin,spent_hdrsi,1); - exit(-1); - } - coin->RTdatabad = 1; - return(0); - } - } else printf("external spent unexpected nonz unspentind [%d]\n",spent_hdrsi); - } - if ( (spentbp= coin->bundles[hdrsi]) == 0 || hdrsi > spent_hdrsi ) - printf("illegal hdrsi.%d when [%d] spentbp.%p\n",hdrsi,spent_hdrsi,spentbp); - 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); - else return(spentbp); - iguana_bundleremove(coin,spent_hdrsi,1); - exit(-1); - return(0); -} - -int32_t iguana_txidfastfind(struct iguana_info *coin,int32_t *heightp,bits256 txid,int32_t lasthdrsi) -{ - uint8_t *sorted,*item; int32_t i,j,val,num,tablesize,*hashtable; uint32_t firstvout; - if ( (sorted= coin->fast[txid.bytes[31]]) != 0 ) - { - memcpy(&num,sorted,sizeof(num)); - memcpy(&tablesize,&sorted[sizeof(num)],sizeof(tablesize)); - if ( (hashtable= coin->fasttables[txid.bytes[31]]) == 0 ) - { - hashtable = (int32_t *)((long)sorted + (1 + num)*16); - //printf("backup hashtable\n"); - } - val = (txid.uints[4] % tablesize); - for (j=0; j= tablesize ) - val = 0; - if ( (i= hashtable[val]) == 0 ) - return(-1); - else - { - if ( i > num ) - { - printf("illegal val.%d vs num.%d tablesize.%d fastfind.%02x\n",i,num,tablesize,txid.bytes[31]); - return(-1); - } - else - { - item = (void *)((long)sorted + i*16); - if ( memcmp(&txid.txid,item,sizeof(uint64_t)) == 0 ) - { - memcpy(&firstvout,&item[sizeof(uint64_t)],sizeof(firstvout)); - memcpy(heightp,&item[sizeof(uint64_t) + sizeof(firstvout)],sizeof(*heightp)); - //printf("i.%d val.%d height.%d firstvout.%d j.%d\n",i,val,*heightp,firstvout,j); - if ( *heightp >= (lasthdrsi+1)*coin->chain->bundlesize ) - { - printf("txidfastfind: unexpected height.%d with lasthdrsi.%d\n",*heightp,lasthdrsi); - return(-1); - } - return(firstvout); - } - else if ( 0 ) - { - int32_t k; - for (k=-16; k<0; k++) - printf("%02x ",item[k]); - printf("<"); - for (k=0; k<16; k++) - printf("%02x ",item[k]); - printf(">"); - for (k=16; k<32; k++) - printf("%02x ",item[k]); - printf("\n"); - printf("txid.%llx vs item.%llx ht.%d 1st.%d\n",(long long)txid.txid,*(long long *)item,*(int32_t *)&item[sizeof(uint64_t)],*(int32_t *)&item[sizeof(uint64_t)+sizeof(uint32_t)]); - } - } - } - } - } - return(-1); -} - -int32_t iguana_unspentindfind(struct iguana_info *coin,int32_t *heightp,bits256 txid,int32_t vout,int32_t lasthdrsi) -{ - struct iguana_txid *tp,TX; int32_t firstvout; - if ( coin->fastfind != 0 && (firstvout= iguana_txidfastfind(coin,heightp,txid,lasthdrsi)) >= 0 ) - { - return(firstvout + vout); - } - if ( (tp= iguana_txidfind(coin,heightp,&TX,txid,lasthdrsi)) != 0 ) - return(tp->firstvout + vout); - return(-1); -} - -int32_t iguana_fastfindadd(struct iguana_info *coin,bits256 txid,int32_t height,uint32_t firstvout) -{ - FILE *fp; - if ( bits256_nonz(txid) != 0 && (fp= coin->fastfps[txid.bytes[31]]) != 0 ) - { - txid.uints[6] = firstvout; - txid.uints[7] = height; - if ( fwrite(&txid,1,sizeof(txid),fp) == sizeof(txid) ) - return(1); - } - return(0); -} - -int64_t iguana_fastfindinitbundle(struct iguana_info *coin,struct iguana_bundle *bp,int32_t iter) -{ - int32_t i; struct iguana_txid *T; struct iguana_ramchaindata *rdata; int64_t n = 0; - if ( (rdata= bp->ramchain.H.data) != 0 ) - { - T = (void *)(long)((long)rdata + rdata->Toffset); - n = rdata->numtxids; - if ( iter == 1 ) - { - for (i=0; ibundleheight + T[i].bundlei,T[i].firstvout); - fprintf(stderr,"[%d:%u] ",bp->hdrsi,(int32_t)n); - } - } - return(n); -} - -static int _bignum_cmp(const void *a,const void *b) -{ - uint8_t *biga,*bigb; int32_t i,diff; - biga = (uint8_t *)a; - bigb = (uint8_t *)b; - for (i=0; i<32; i++) - { - if ( (diff= (biga[i] - bigb[i])) > 0 ) - return(1); - else if ( diff < 0 ) - return(-1); - } - return(0); -} - -uint32_t iguana_fastfindinit(struct iguana_info *coin) -{ - int32_t i,j,iter,num,tablesize,*hashtable; uint8_t *sorted; char fname[1024]; - //if ( strcmp("BTC",coin->symbol) != 0 ) - // return(0); - if ( coin->fastfind != 0 ) - return(coin->fastfind); - for (iter=0; iter<2; iter++) - { - for (i=0; i<0x100; i++) - { - sprintf(fname,"DB/%s%s/fastfind/%02x.all",iter!=0?"ro/":"",coin->symbol,i), OS_compatible_path(fname); - if ( (coin->fast[i]= OS_mapfile(fname,&coin->fastsizes[i],0)) == 0 ) - break; - else - { - fprintf(stderr,"."); - sorted = coin->fast[i]; - if ( 0 ) - { - coin->fast[i] = calloc(1,coin->fastsizes[i]); - memcpy(coin->fast[i],sorted,coin->fastsizes[i]); - munmap(sorted,coin->fastsizes[i]); - } - sorted = coin->fast[i]; - memcpy(&num,sorted,sizeof(num)); - memcpy(&tablesize,&sorted[sizeof(num)],sizeof(tablesize)); - if ( (num+1)*16 + tablesize*sizeof(*hashtable) == coin->fastsizes[i] ) - { - hashtable = (int32_t *)((long)sorted + (1 + num)*16); - if ( 0 ) - { - coin->fasttables[i] = calloc(tablesize,sizeof(*hashtable)); - memcpy(coin->fasttables[i],hashtable,tablesize * sizeof(*hashtable)); - } - } - else - { - printf("size error num.%d tablesize.%d -> %lu vs %ld\n",num,tablesize,(num+1)*16 + tablesize*sizeof(*hashtable),coin->fastsizes[i]); - break; - } - } - } - if ( i == 0x100 ) - { - coin->fastfind = (uint32_t)time(NULL); - printf("initialized fastfind.%s iter.%d\n",coin->symbol,iter); - return(coin->fastfind); - } - else - { - for (j=0; jfast[i],coin->fastsizes[i]); - free(coin->fasttables[i]); - coin->fast[i] = 0; - coin->fastsizes[i] = 0; - } - } - } - return(0); -} - -int64_t iguana_fastfindcreate(struct iguana_info *coin) -{ - int32_t i,j,val,iter,errs,num,ind,tablesize,*hashtable; bits256 *sortbuf,hash2; long allocsize; struct iguana_bundle *bp; char fname[512]; uint8_t buf[16]; int64_t total = 0; - if ( coin->current != 0 && coin->bundlescount == coin->current->hdrsi+1 ) - { - sprintf(fname,"DB/%s/fastfind",coin->symbol), OS_ensure_directory(fname); - for (i=0; i<0x100; i++) - { - sprintf(fname,"DB/%s/fastfind/%02x",coin->symbol,i), OS_compatible_path(fname); - if ( (coin->fastfps[i]= fopen(fname,"wb")) == 0 ) - break; - } - if ( i == 0x100 ) - { - for (iter=0; iter<2; iter++) - { - total = 0; - for (i=0; ibundlescount-1; i++) - if ( (bp= coin->bundles[i]) != 0 ) - total += iguana_fastfindinitbundle(coin,bp,iter); - printf("iguana_fastfindinit iter.%d total.%lld\n",iter,(long long)total); - } - for (i=errs=0; i<0x100; i++) - { - fclose(coin->fastfps[i]); - sprintf(fname,"DB/%s/fastfind/%02x",coin->symbol,i), OS_compatible_path(fname); - //printf("%s\n",fname); - if ( (sortbuf= OS_filestr(&allocsize,fname)) != 0 ) - { - OS_removefile(fname,0); - num = (int32_t)allocsize/sizeof(bits256); - qsort(sortbuf,num,sizeof(bits256),_bignum_cmp); - strcat(fname,".all"); - if ( (coin->fastfps[i]= fopen(fname,"wb")) != 0 ) - { - tablesize = (num << 1); - hashtable = calloc(sizeof(*hashtable),tablesize); - for (ind=1; ind<=num; ind++) - { - hash2 = sortbuf[ind-1]; - val = (hash2.uints[4] % tablesize); - for (j=0; j= tablesize ) - val = 0; - if ( hashtable[val] == 0 ) - { - hashtable[val] = ind; - break; - } - } - } - memset(&hash2,0,sizeof(hash2)); - hash2.uints[0] = num; - hash2.uints[1] = tablesize; - for (j=0; j<=num; j++) - { - memcpy(buf,&hash2.txid,sizeof(hash2.txid)); - memcpy(&buf[sizeof(hash2.txid)],&hash2.uints[6],sizeof(hash2.uints[6])); - memcpy(&buf[sizeof(hash2.txid) + sizeof(hash2.uints[6])],&hash2.uints[7],sizeof(hash2.uints[7])); - fwrite(buf,1,sizeof(buf),coin->fastfps[i]); - //fwrite(hash2,1,sizeof(hash2),coin->fastfps[i]); - if ( j < num ) - { - hash2 = sortbuf[j]; - //char str[65]; printf("%d %s\n",j,bits256_str(str,hash2)); - } - } - if ( fwrite(hashtable,sizeof(*hashtable),tablesize,coin->fastfps[i]) == tablesize ) - { - fclose(coin->fastfps[i]); - coin->fastfps[i] = 0; - if ( (coin->fast[i]= OS_mapfile(fname,&coin->fastsizes[i],0)) != 0 ) - { - } else errs++; - printf("%s fastfind.[%02x] num.%d tablesize.%d errs.%d %p[%ld]\n",fname,i,num,tablesize,errs,coin->fast[i],coin->fastsizes[i]); - } - else - { - printf("error saving (%s)\n",fname); - OS_removefile(fname,0); - fclose(coin->fastfps[i]); - coin->fastfps[i] = 0; - } - free(hashtable); - } else printf("couldnt overwrite (%s)\n",fname); - free(sortbuf); - } else printf("couldnt load sortbuf (%s)\n",fname); - } - printf("initialized with errs.%d\n",errs); - if ( errs == 0 ) - coin->fastfind = (uint32_t)time(NULL); - } - } - return(total); -} - -struct iguana_bundle *iguana_fastexternalspent(struct iguana_info *coin,bits256 *prevhashp,uint32_t *unspentindp,struct iguana_ramchain *ramchain,int32_t spent_hdrsi,struct iguana_spend *s) -{ - int32_t prev_vout,height,hdrsi,unspentind; uint32_t ind; - struct iguana_txid *T; bits256 *X; bits256 prev_hash; struct iguana_ramchaindata *rdata; - if ( (rdata= ramchain->H.data) == 0 ) - return(0); - hdrsi = spent_hdrsi; - *unspentindp = 0; - memset(prevhashp,0,sizeof(*prevhashp)); - if ( (prev_vout= s->prevout) >= 0 ) - { - ind = s->spendtxidind & ~(1 << 31); - if ( s->external != 0 ) - { - if ( ind < rdata->numexternaltxids ) - { - char str[65]; //double duration,startmillis = OS_milliseconds(); - X = (void *)(long)((long)rdata + rdata->Xoffset); - *prevhashp = prev_hash = X[ind]; - if ( (unspentind= iguana_unspentindfind(coin,&height,prev_hash,prev_vout,spent_hdrsi-1)) != 0 ) - //if ( (firstvout= iguana_txidfastfind(coin,&height,prev_hash,spent_hdrsi-1)) >= 0 ) - { - /*duration = (OS_milliseconds() - startmillis); - if ( ((uint64_t)coin->txidfind_num % 100) == 1 ) - printf("[%d] iguana_fasttxidfind.[%.0f] ave %.2f micros, total %.2f seconds | duration %.3f millis\n",spent_hdrsi,coin->txidfind_num,(coin->txidfind_totalmillis*1000.)/coin->txidfind_num,coin->txidfind_totalmillis/1000.,duration); - coin->txidfind_totalmillis += duration; - coin->txidfind_num += 1.;*/ - *unspentindp = unspentind;//firstvout + prev_vout; - hdrsi = height / coin->chain->bundlesize; - if ( hdrsi >= 0 && hdrsi < coin->bundlescount ) - return(coin->bundles[hdrsi]); - } - else - { - printf("couldnt fastfind (%s)\n",bits256_str(str,prev_hash)); - } - } else return(0); - } - else if ( ind < rdata->numtxids ) - { - T = (void *)(long)((long)rdata + rdata->Toffset); - *prevhashp = T[ind].txid; - *unspentindp = T[ind].firstvout + s->prevout; - return(coin->bundles[hdrsi]); - } - } - return(0); -} - -cJSON *ramchain_unspentjson(struct iguana_unspent *up,uint32_t unspentind) -{ - cJSON *item = cJSON_CreateObject(); - jaddnum(item,"hdrsi",up->hdrsi); - jaddnum(item,"pkind",up->pkind); - jaddnum(item,"unspentind",unspentind); - jaddnum(item,"prevunspentind",up->prevunspentind); - jadd64bits(item,"satoshis",up->value); - jaddnum(item,"txidind",up->txidind); - jaddnum(item,"vout",up->vout); - jaddnum(item,"type",up->type); - jaddnum(item,"fileid",up->fileid); - jaddnum(item,"scriptpos",up->scriptpos); - jaddnum(item,"scriptlen",up->scriptlen); - return(item); -} - -cJSON *iguana_unspentjson(struct supernet_info *myinfo,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_waddress *waddr; int32_t height; char scriptstr[8192],asmstr[sizeof(scriptstr)+1024]; cJSON *item; uint32_t checkind; - item = cJSON_CreateObject(); - jaddbits256(item,"txid",T[up->txidind].txid); - jaddnum(item,"vout",up->vout); - jaddstr(item,"address",coinaddr); - 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 ( (checkind= iguana_unspentindfind(coin,&height,T[up->txidind].txid,up->vout,coin->bundlescount-1)) != 0 ) - { - jaddnum(item,"confirmations",coin->blocks.hwmchain.height - height + 1); - jaddnum(item,"checkind",checkind); - } - if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,coinaddr)) != 0 ) - { - jaddstr(item,"account",wacct->account); - jadd(item,"spendable",jtrue()); - } else jadd(item,"spendable",jfalse()); - jadd(item,"unspent",ramchain_unspentjson(up,unspentind)); - return(item); -} - -struct iguana_pkhash *iguana_pkhashfind(struct iguana_info *coin,struct iguana_ramchain **ramchainp,int64_t *depositsp,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,numpkinds,i; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; struct iguana_ramchaindata *rdata; struct iguana_account *ACCTS; - *depositsp = 0; - *ramchainp = 0; - *lastunspentindp = 0; - for (i=firsti; ibundlescount&&i<=endi; i++) - { - if ( (bp= coin->bundles[i]) != 0 ) - { - if ( 0 && coin->RTramchain_busy != 0 ) - { - printf("iguana_pkhashfind: unexpected access when RTramchain_busy\n"); - return(0); - } - ramchain = (bp != coin->current) ? &bp->ramchain : &coin->RTramchain; - if ( (rdata= ramchain->H.data) != 0 ) - { - numpkinds = rdata->numpkinds; - PKbits = (void *)(long)((long)rdata + rdata->PKoffset); - P = (void *)(long)((long)rdata + rdata->Poffset); - if ( bp == coin->current ) - ACCTS = ramchain->A; - else ACCTS = (void *)(long)((long)rdata + rdata->Aoffset); - if ( (pkind= iguana_sparseaddpk(PKbits,rdata->pksparsebits,rdata->numpksparse,rmd160,P,0,ramchain)) > 0 && pkind < numpkinds ) - { - *ramchainp = ramchain; - *depositsp = ACCTS[pkind].total; - *lastunspentindp = ACCTS[pkind].lastunspentind; - *p = P[pkind]; -printf("[%d] return pkind.%u %.8f last.%u ACCTS.%p %p\n",i,pkind,dstr(*depositsp),*lastunspentindp,ACCTS,ramchain->A); - return(p); - } - else if ( pkind != 0 ) - printf("[%d] not found pkind.%d vs num.%d RT.%d rdata.%p\n",i,pkind,rdata->numpkinds,bp->isRT,rdata); - } else printf("%s.[%d] error null rdata isRT.%d\n",coin->symbol,i,bp->isRT); - } - } - return(0); -} - -char *iguana_bundleaddrs(struct iguana_info *coin,int32_t hdrsi) -{ - uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind,numpkinds; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; cJSON *retjson; char rmdstr[41]; - if ( (bp= coin->bundles[hdrsi]) != 0 ) - { - if ( 0 && coin->RTramchain_busy != 0 ) - { - printf("iguana_bundleaddrs: unexpected access when RTramchain_busy\n"); - return(0); - } - ramchain = &bp->ramchain;//(bp->isRT != 0) ? &bp->ramchain : &coin->RTramchain; - if ( ramchain->H.data != 0 ) - { - numpkinds = ramchain->H.data->numpkinds;//(bp->isRT != 0) ? ramchain->H.data->numpkinds : ramchain->pkind; - 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; pkindrmd160,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\"}")); -} - -int32_t iguana_uheight(struct iguana_info *coin,int32_t bundleheight,struct iguana_txid *T,int32_t numtxids,struct iguana_unspent *up) -{ - if ( up->txidind > 0 && up->txidind < numtxids ) - return(bundleheight + T[up->txidind].bundlei); - else return(bundleheight); -} - -int64_t iguana_pkhashbalance(struct supernet_info *myinfo,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,int32_t lastheight,int32_t minconf,int32_t maxconf) -{ - struct iguana_unspent *U; struct iguana_utxo *U2; struct iguana_spend *S; int32_t uheight,spentheight; uint32_t pkind=0,unspentind; int64_t spent = 0,checkval,deposits = 0; struct iguana_txid *T; struct iguana_account *A2; struct iguana_ramchaindata *rdata = 0; int64_t RTspend = 0; - *spentp = *nump = 0; - if ( 0 && coin->RTramchain_busy != 0 ) - { - printf("iguana_pkhashbalance: unexpected access when RTramchain_busy\n"); - return(0); - } - if ( ramchain->Uextras == 0 || (rdata= ramchain->H.data) == 0 ) - { - printf("iguana_pkhashbalance: unexpected null spents.%p or rdata.%p\n",ramchain->Uextras,rdata); - return(0); - } - unspentind = lastunspentind; - U = (void *)(long)((long)rdata + rdata->Uoffset); - T = (void *)(long)((long)rdata + rdata->Toffset); - RTspend = 0; - if ( lastheight == 0 ) - lastheight = IGUANA_MAXHEIGHT; - while ( unspentind > 0 ) - { - (*nump)++; - uheight = iguana_uheight(coin,ramchain->height,T,rdata->numtxids,&U[unspentind]); - if ( uheight < lastheight ) - { - deposits += U[unspentind].value; - if ( lastheight < 0 || iguana_spentflag(coin,&RTspend,&spentheight,ramchain,hdrsi,unspentind,lastheight,minconf,maxconf,U[unspentind].value) == 0 ) - { - if ( array != 0 ) - jaddi(array,iguana_unspentjson(myinfo,coin,hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33)); - } else spent += U[unspentind].value; - if ( p->pkind != U[unspentind].pkind ) - printf("warning: [%d] p->pkind.%u vs U->pkind.%u for u%d\n",hdrsi,p->pkind,U[unspentind].pkind,unspentind); - } - pkind = p->pkind; - unspentind = U[unspentind].prevunspentind; - } - if ( lastheight > 0 && (A2= ramchain->A2) != 0 && (U2= ramchain->Uextras) != 0 ) - { - S = (void *)(long)((long)rdata + rdata->Soffset); - unspentind = A2[pkind].lastunspentind; - checkval = 0; - while ( unspentind > 0 ) - { - uheight = iguana_uheight(coin,ramchain->height,T,rdata->numtxids,&U[unspentind]); - if ( uheight < lastheight ) - { - checkval += U[unspentind].value; - //printf("u%u %.8f spentflag.%d prev.%u fromheight.%d\n",unspentind,dstr(U[unspentind].value),U2[unspentind].spentflag,U2[unspentind].prevunspentind,U2[unspentind].fromheight); - } - unspentind = U2[unspentind].prevunspentind; - } - if ( fabs(spent - checkval - RTspend) > SMALLVAL ) - printf("spend %s: [%d] deposits %.8f spent %.8f check %.8f (%.8f) vs A2[%u] %.8f\n",lastheight==IGUANA_MAXHEIGHT?"checkerr":"",hdrsi,dstr(deposits),dstr(spent),dstr(checkval)+dstr(RTspend),dstr(*spentp),pkind,dstr(A2[pkind].total)); - } - (*spentp) = spent; - //printf("spent %.8f, RTspent %.8f deposits %.8f\n",dstr(spent),dstr(RTspend),dstr(deposits)); - return(deposits - spent); -} - -int32_t iguana_pkhasharray(struct supernet_info *myinfo,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 lastheight) -{ - int32_t i,n,m; int64_t spent,deposits,netbalance,total; uint32_t lastunspentind; struct iguana_ramchain *ramchain; struct iguana_bundle *bp; - if ( 0 && coin->RTramchain_busy != 0 ) - { - printf("iguana_pkhasharray: unexpected access when RTramchain_busy\n"); - return(-1); - } - if ( lastheight == 0 ) - lastheight = IGUANA_MAXHEIGHT; - for (total=i=n=0; ibundlescount; i++) - { - if ( (bp= coin->bundles[i]) == 0 ) - continue; - if ( lastheight > 0 && bp->bundleheight > lastheight ) - break; - if ( (coin->blocks.hwmchain.height - (bp->bundleheight + bp->n - 1)) > maxconf ) - continue; - if ( (coin->blocks.hwmchain.height - bp->bundleheight) < minconf ) - break; - if ( iguana_pkhashfind(coin,&ramchain,&deposits,&lastunspentind,&P[n],rmd160,i,i) != 0 ) - { - if ( (netbalance= iguana_pkhashbalance(myinfo,coin,array,&spent,&m,ramchain,&P[n],lastunspentind,rmd160,coinaddr,pubkey33,i,lastheight,minconf,maxconf)) != deposits-spent && lastheight == IGUANA_MAXHEIGHT && minconf == 1 && maxconf > coin->blocks.hwmchain.height ) - { - printf("pkhash balance mismatch from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",m,dstr(netbalance),dstr(deposits),dstr(spent),dstr(deposits)-dstr(spent)); - } - else - { - //printf("pkhash balance.[%d] from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",i,m,dstr(netbalance),dstr(deposits),dstr(spent),dstr(deposits)-dstr(spent)); - 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); -} - -int64_t iguana_unspents(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,uint8_t *rmdarray,int32_t numrmds,int32_t lastheight) -{ - int64_t total,sum=0; struct iguana_pkhash *P; uint8_t *addrtypes,*pubkeys; int32_t i,flag = 0; char coinaddr[64]; - if ( 0 && coin->RTramchain_busy != 0 ) - { - printf("iguana_pkhasharray: unexpected access when RTramchain_busy\n"); - return(sum); - } - if ( rmdarray == 0 ) - rmdarray = iguana_walletrmds(myinfo,coin,&numrmds), flag++; - if ( numrmds > 0 && rmdarray != 0 ) - { - 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],lastheight); - printf("i.%d of %d: %s %.8f\n",i,numrmds,coinaddr,dstr(total)); - sum += total; - } - printf("sum %.8f\n",dstr(sum)); - free(P); - } - if ( flag != 0 && rmdarray != 0 ) - free(rmdarray); - return(sum); -} - -static inline int32_t _iguana_spendvectorconv(struct iguana_spendvector *ptr,struct iguana_unspent *u,int32_t numpkinds,int32_t hdrsi,uint32_t unspentind) -{ - uint32_t spent_pkind = 0; - if ( (spent_pkind= u->pkind) != 0 && spent_pkind < numpkinds ) - { - ptr->pkind = spent_pkind; - ptr->value = u->value; - ptr->tmpflag = 0; - return(spent_pkind); - } else printf("spendvectorconv [%d] u%d pkind.%u/num %u\n",hdrsi,unspentind,u->pkind,numpkinds); - return(0); -} - -uint32_t iguana_spendvectorconv(struct iguana_info *coin,struct iguana_spendvector *ptr,struct iguana_bundle *bp) -{ - static uint64_t count,converted,errs; - struct iguana_bundle *spentbp; struct iguana_unspent *spentU; uint32_t spent_pkind; - count++; - if ( 0 && (count % 1000000) == 0 ) - printf("iguana_spendvectorconv.[%llu] errs.%llu converted.%llu %.2f%%\n",(long long)count,(long long)errs,(long long)converted,100. * (long long)converted/count); - if ( ptr->tmpflag != 0 ) - { - if ( ptr->hdrsi >= 0 && ptr->hdrsi < coin->bundlescount && (spentbp= coin->bundles[ptr->hdrsi]) != 0 ) - { - spentU = (void *)(long)((long)spentbp->ramchain.H.data + spentbp->ramchain.H.data->Uoffset); - if ( (spent_pkind= _iguana_spendvectorconv(ptr,&spentU[ptr->unspentind],spentbp->ramchain.H.data->numpkinds,ptr->hdrsi,ptr->unspentind)) != 0 ) - converted++; - else printf("illegal [%d].u%u pkind.%u vs %u\n",ptr->hdrsi,ptr->unspentind,spent_pkind,spentbp->ramchain.H.data->numpkinds); - } else printf("illegal [%d].u%u\n",ptr->hdrsi,ptr->unspentind); - errs++; - return(0); - } //else printf("[%d] tmpflag.%d u%d %.8f p%u\n",ptr->hdrsi,ptr->tmpflag,ptr->unspentind,dstr(ptr->value),ptr->pkind); - return(ptr->pkind); -} - -int32_t iguana_spendvectorsave(struct iguana_info *coin,struct iguana_bundle *bp,struct iguana_ramchain *ramchain,struct iguana_spendvector *ptr,int32_t emit,int32_t n) -{ - int32_t i,retval = -1; FILE *fp; char fname[1024],str[65]; long fsize; bits256 zero,sha256; - if ( ptr == 0 || (bp->hdrsi != 0 && ptr == bp->ramchain.Xspendinds) ) - { - //printf("iguana_spendvectorsave.[%d] ptr.%p Xspendinds\n",bp->hdrsi,ptr); - return(0); - } - memset(zero.bytes,0,sizeof(zero)); - for (i=0; ihdrsi,i,emit,n); - return(-1); - } - sprintf(fname,"%s/%s/spends/%s.%d",GLOBAL_DBDIR,coin->symbol,bits256_str(str,bp->hashes[0]),bp->bundleheight); - vcalc_sha256(0,sha256.bytes,(void *)ptr,(int32_t)(sizeof(*ptr) * emit)); - 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), fp = 0; - bp->Xvalid = 0; - if ( iguana_Xspendmap(coin,ramchain,bp) < 0 ) - printf("error mapping Xspendmap.(%s)\n",fname); - else - { - printf("created.(%s) %p[%d]\n",fname,bp->ramchain.Xspendinds,bp->ramchain.numXspends); - retval = 0; - } - } - if ( fp != 0 ) - fclose(fp); - //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("iguana_spendvectors: Error creating.(%s)\n",fname); - return(retval); -} - -int32_t iguana_spendvectors(struct iguana_info *coin,struct iguana_bundle *bp,struct iguana_ramchain *ramchain,int32_t starti,int32_t numblocks,int32_t convertflag,int32_t iterate) -{ - static uint64_t total,emitted; - int32_t iter,spendind,n=0,txidind,errs=0,emit=0,i,j,k; double startmillis; bits256 prevhash; - uint32_t spent_unspentind,spent_pkind,now,starttime; struct iguana_ramchaindata *rdata; - struct iguana_bundle *spentbp; struct iguana_blockRO *B; struct iguana_spendvector *ptr; - struct iguana_unspent *u,*spentU; struct iguana_txid *T; char str[65]; - struct iguana_spend *S,*s; //void *fastfind = 0; - //printf("iguana_spendvectors.[%d] gen.%d ramchain data.%p txbits.%p\n",bp->hdrsi,bp->bundleheight,ramchain->H.data,ramchain->txbits); - if ( (rdata= ramchain->H.data) == 0 || (n= rdata->numspends) < 1 ) - { - printf("iguana_spendvectors.[%d]: no rdata.%p %d\n",bp->hdrsi,rdata,n); - return(0); - } - B = (void *)(long)((long)rdata + rdata->Boffset); - S = (void *)(long)((long)rdata + rdata->Soffset); - T = (void *)(long)((long)rdata + rdata->Toffset); - if ( ramchain->Xspendinds != 0 ) - { - bp->tmpspends = ramchain->Xspendinds; - bp->numtmpspends = ramchain->numXspends; - bp->utxofinish = (uint32_t)time(NULL); - bp->balancefinish = 0; - //printf("iguana_spendvectors.[%d]: already have Xspendinds[%d]\n",bp->hdrsi,ramchain->numXspends); - return(0); - } - ptr = mycalloc('x',sizeof(*ptr),n); - total += n; - startmillis = OS_milliseconds(); - if ( 0 && strcmp(coin->symbol,"BTC") == 0 ) - printf("start UTXOGEN.%d max.%d ptr.%p millis.%.3f\n",bp->bundleheight,n,ptr,startmillis); - starttime = (uint32_t)time(NULL); - iguana_ramchain_prefetch(coin,&bp->ramchain,3); - for (iter=0; iter<=iterate; iter++) - { - if ( iterate != 0 ) - { - //fastfind = coin->fast[iter]; - //coin->fast[iter] = calloc(1,coin->fastsizes[iter]); - //memcpy(coin->fast[iter],fastfind,coin->fastsizes[iter]); - } - txidind = B[starti].firsttxidind; - spendind = B[starti].firstvin; - for (i=starti; icurrent && (spendind % 10000) == 0 ) - printf("iter.%02x [%-3d:%4d] spendvectors elapsed t.%-3d spendind.%d\n",iter,bp->hdrsi,i,(uint32_t)time(NULL)-starttime,spendind); -#endif - u = 0; - spentbp = 0; - s = &S[spendind]; - if ( s->external != 0 && s->prevout >= 0 ) - { - if ( coin->fastfind != 0 ) - { - spentbp = iguana_fastexternalspent(coin,&prevhash,&spent_unspentind,ramchain,bp->hdrsi,s); - } - else if ( spentbp == 0 ) - { - if ( (spentbp= iguana_externalspent(coin,&prevhash,&spent_unspentind,ramchain,bp->hdrsi,s,2)) != 0 ) - { - if ( coin->fastfind != 0 ) - printf("found prevhash using slow, not fast\n"); - } - } - if ( iterate != 0 && (spentbp == 0 || spentbp->hdrsi != iter) ) - continue; - if ( bits256_nonz(prevhash) == 0 ) - continue; - if ( spentbp != 0 && spentbp->ramchain.H.data != 0 ) - { - if ( spentbp == bp ) - { - char str[65]; - printf("unexpected spendbp: height.%d bp.[%d] U%d <- S%d.[%d] [ext.%d %s prev.%d]\n",bp->bundleheight+i,spentbp->hdrsi,spent_unspentind,spendind,bp->hdrsi,s->external,bits256_str(str,prevhash),s->prevout); - errs++; - break; - } - if ( convertflag != 0 ) - { - if ( coin->PREFETCHLAG > 0 && now >= spentbp->lastprefetch+coin->PREFETCHLAG ) - { - printf("prefetch[%d] from.[%d] lag.%d\n",spentbp->hdrsi,bp->hdrsi,now - spentbp->lastprefetch); - iguana_ramchain_prefetch(coin,&spentbp->ramchain,2); - spentbp->lastprefetch = now; - } - spentU = (void *)(long)((long)spentbp->ramchain.H.data + spentbp->ramchain.H.data->Uoffset); - u = &spentU[spent_unspentind]; - if ( (spent_pkind= u->pkind) != 0 && spent_pkind < spentbp->ramchain.H.data->numpkinds ) - { - memset(&ptr[emit],0,sizeof(ptr[emit])); - if ( (ptr[emit].unspentind= spent_unspentind) != 0 && spentbp->hdrsi < bp->hdrsi ) - { - ptr[emit].fromheight = bp->bundleheight + i; - ptr[emit].hdrsi = spentbp->hdrsi; - ptr[emit].pkind = spent_pkind; - ptr[emit].value = u->value; - //printf("ht.%d [%d] SPENDVECTOR u%d %.8f p%u\n",ptr[emit].fromheight,ptr[emit].hdrsi,ptr[emit].unspentind,dstr(ptr[emit].value),ptr[emit].pkind); - //printf("(%d u%d).%d ",spentbp->hdrsi,unspentind,emit); - emit++; - } - else - { - printf("spendvectors: null unspentind for spendind.%d hdrsi.%d [%d]\n",spendind,spentbp->hdrsi,bp->hdrsi); - errs++; - break; - } - } - else - { - errs++; - printf("spendvectors: unresolved spendind.%d hdrsi.%d\n",spendind,bp->hdrsi); - break; - } - } - else - { - memset(&ptr[emit],0,sizeof(ptr[emit])); - ptr[emit].hdrsi = spentbp->hdrsi; - ptr[emit].unspentind = spent_unspentind; - ptr[emit].fromheight = bp->bundleheight + i; - ptr[emit].tmpflag = 1; - if ( 0 && bp == coin->current ) - printf("fromht.%d spends [%d] TMPVECTOR u%d s%u\n",ptr[emit].fromheight,ptr[emit].hdrsi,ptr[emit].unspentind,spendind); - emit++; - } - } - else - { - errs++; - printf("spendvectors: error resolving external spendind.%d hdrsi.%d\n",spendind,bp->hdrsi); - break; - } - } - } - } - } - /*if ( iterate != 0 ) - { - free(coin->fast[iter]); - coin->fast[iter] = fastfind; - }*/ - if ( txidind != ramchain->H.data->numtxids && txidind != ramchain->H.txidind ) - { - printf("spendvectors: numtxid.%d != bp numtxids %d/%d\n",txidind,ramchain->H.txidind,ramchain->H.data->numtxids); - errs++; - } - if ( spendind != ramchain->H.data->numspends && spendind != ramchain->H.spendind ) - { - printf("spendvectors: spendind.%d != bp numspends %d/%d\n",spendind,ramchain->H.spendind,ramchain->H.data->numspends); - errs++; - } - } - if ( errs == 0 && emit >= 0 ) - { - emitted += emit; - if ( convertflag == 0 ) - { - if ( bp->tmpspends != 0 ) - { - if ( bp->tmpspends != ramchain->Xspendinds && emit > 0 ) - { - // printf("spendvectors: RT [%d] numtmpspends.%d vs starti.%d emit.%d\n",bp->hdrsi,bp->numtmpspends,starti,emit); - bp->tmpspends = myrealloc('x',bp->tmpspends,sizeof(*ptr)*bp->numtmpspends,sizeof(*ptr)*(bp->numtmpspends+emit)); - memcpy(&bp->tmpspends[bp->numtmpspends],ptr,sizeof(*ptr)*emit); - bp->numtmpspends += emit; - } - } - else if ( emit > 0 ) - { - bp->tmpspends = myrealloc('x',ptr,sizeof(*ptr)*n,sizeof(*ptr)*emit); - bp->numtmpspends = emit; - //printf("ALLOC tmpspends.[%d]\n",bp->hdrsi); - ptr = 0; - } - if ( 0 && bp == coin->current ) - printf("spendvectors.[%d]: tmpspends.%p[%d] after += emit.%d X.%p\n",bp->hdrsi,bp->tmpspends,bp->numtmpspends,emit,bp->ramchain.Xspendinds); - } else errs = -iguana_spendvectorsave(coin,bp,ramchain,ptr!=0?ptr:bp->tmpspends,emit,n); - } - if ( ptr != 0 ) - myfree(ptr,sizeof(*ptr) * n); - //if ( bp != coin->current ) - printf("UTXO [%4d].%-6d dur.%-2d [milli %8.3f] vectors %-6d err.%d [%5.2f%%] %7d %9s of %d\n",bp->hdrsi,bp->numtmpspends,(uint32_t)time(NULL)-starttime,OS_milliseconds()-startmillis,spendind,errs,100.*(double)emitted/(total+1),emit,mbstr(str,sizeof(*ptr) * emit),n); - return(-errs); -} - -int32_t iguana_balancegen(struct iguana_info *coin,int32_t incremental,struct iguana_bundle *bp,int32_t starti,int32_t endheight,int32_t startemit) -{ - uint32_t spent_unspentind,spent_pkind,txidind,h,i,j,endi,k,now; uint64_t spent_value; - struct iguana_ramchain *ramchain; struct iguana_ramchaindata *rdata; - struct iguana_spendvector *spend; struct iguana_unspent *spentU,*u; struct iguana_spendvector *Xspendinds; - struct iguana_txid *T; struct iguana_blockRO *B; struct iguana_bundle *spentbp; - int32_t spent_hdrsi,spendind,n,numXspends,errs=0,emit=0; struct iguana_spend *S,*s; - ramchain = &bp->ramchain; //(bp == coin->current) ? &coin->RTramchain : &bp->ramchain; - if ( (rdata= ramchain->H.data) == 0 || (n= ramchain->H.data->numspends) < 1 ) - return(-1); - S = (void *)(long)((long)rdata + rdata->Soffset); - B = (void *)(long)((long)rdata + rdata->Boffset); - T = (void *)(long)((long)rdata + rdata->Toffset); - numXspends = ramchain->numXspends; - if ( (Xspendinds= ramchain->Xspendinds) == 0 ) - { - numXspends = bp->numtmpspends; - if ( (Xspendinds= bp->tmpspends) == 0 ) - { - //printf("iguana_balancegen.%d: no Xspendinds[%d]\n",bp->hdrsi,numXspends); - //return(-1); - } - } - endi = (endheight % bp->n); - txidind = B[starti].firsttxidind; - spendind = B[starti].firstvin; - emit = startemit; - if ( coin->RTheight == 0 || bp->bundleheight+bp->n < coin->RTheight ) - fprintf(stderr,"BALANCEGEN.[%d] %p[%d] starti.%d s%d <-> endi.%d s%d startemit.%d\n",bp->hdrsi,Xspendinds,numXspends,starti,spendind,endi,B[endi].firstvin+B[endi].numvins,startemit); - for (i=starti; i<=endi; i++) - { - now = (uint32_t)time(NULL); - if ( 0 && bp == coin->current ) - printf("hdrs.[%d] B[%d] 1st txidind.%d txn_count.%d firstvin.%d firstvout.%d\n",bp->hdrsi,i,B[i].firsttxidind,B[i].txn_count,B[i].firstvin,B[i].firstvout); - if ( txidind != B[i].firsttxidind || spendind != B[i].firstvin ) - { - printf("balancegen: txidind %u != %u B[%d].firsttxidind || spendind %u != %u B[%d].firstvin errs.%d\n",txidind,B[i].firsttxidind,i,spendind,B[i].firstvin,i,errs); - return(-1); - } - for (j=0; jcurrent ) - printf("starti.%d txidind.%d txi.%d numvins.%d spendind.%d\n",i,txidind,j,T[txidind].numvins,spendind); - for (k=0; kexternal != 0 && s->prevout >= 0 ) - { - if ( emit >= numXspends ) - errs++; - else if ( Xspendinds != 0 ) - { - spend = &Xspendinds[emit++]; - spent_unspentind = spend->unspentind; - spent_value = spend->value; - spent_pkind = spend->pkind; - spent_hdrsi = spend->hdrsi; - h = spend->fromheight; - } - if ( 0 && bp == coin->current ) - printf("external prevout.%d (emit.%d numX.%d) %p u%d p%d errs.%d spent_hdrsi.%d s%u\n",s->prevout,emit,numXspends,Xspendinds,spent_unspentind,spent_pkind,errs,spent_hdrsi,spendind); - } - else if ( s->prevout >= 0 ) - { - h = bp->bundleheight + i; - spent_hdrsi = bp->hdrsi; - if ( s->spendtxidind != 0 && s->spendtxidind < rdata->numtxids ) - { - spent_unspentind = T[s->spendtxidind].firstvout + s->prevout; - spentU = (void *)(long)((long)rdata + rdata->Uoffset); - u = &spentU[spent_unspentind]; - if ( (spent_pkind= u->pkind) != 0 && spent_pkind < rdata->numpkinds ) - spent_value = u->value; - /*found spend d9151... txidind.1083097 [202] s3163977 - //found spend d9151... txidind.1083097 [202] s4033628 - if ( spent_hdrsi == 202 && (spendind == 3163977 || spendind == 4033628) ) - printf("internal spend.%d spendtxidind.%d 1st.%d U.(prevout.%d u%u pkind.%u %.8f)\n",spendind,txidind,T[s->spendtxidind].firstvout,s->prevout,spent_unspentind,u->pkind,dstr(u->value));*/ - } - else //if ( i > 0 || j > 0 || k > 0 ) - { - printf("iguana_balancegen [%d] txidind overflow %u vs %u (%d %d %d)\n",bp->hdrsi,s->spendtxidind,rdata->numtxids,i,j,k); - errs++; - } - } - else continue; - spentbp = 0; - if ( (spentbp= coin->bundles[spent_hdrsi]) != 0 && spent_unspentind > 0 && spent_pkind > 0 ) - { - if ( 0 && bp == coin->current ) - printf("[%d] spendind.%u -> [%d] u%d\n",bp->hdrsi,spendind,spent_hdrsi,spent_unspentind); - if ( iguana_volatileupdate(coin,incremental,spentbp == coin->current ? &coin->RTramchain : &spentbp->ramchain,spent_hdrsi,spent_unspentind,spent_pkind,spent_value,spendind,h) < 0 ) - errs++; - } - else //if ( Xspendinds != 0 ) - { - errs++; - printf("iguana_balancegen: spendind.%u external.%d error spentbp.%p with unspentind.%d pkind.%u [%d] (%d %d %d)\n",spendind,s->external,spentbp,spent_unspentind,spent_pkind,spent_hdrsi,i,j,k); - } - } - } - } - if ( txidind != bp->ramchain.H.data->numtxids && (bp != coin->current || txidind != ramchain->H.txidind) ) - { - printf("numtxid.%d != bp numtxids %d/%d\n",txidind,bp->ramchain.H.txidind,bp->ramchain.H.data->numtxids); - errs++; - } - if ( spendind != ramchain->H.data->numspends && (bp != coin->current || spendind != ramchain->H.spendind) ) - { - printf("spendind.%d != bp numspends %d/%d\n",spendind,bp->ramchain.H.spendind,bp->ramchain.H.data->numspends); - errs++; - } - if ( emit != numXspends ) - { - printf("iguana_balancegen: emit %d != %d ramchain->numXspends\n",emit,numXspends); - errs++; - } - if ( errs == 0 ) - bp->balancefinish = (uint32_t)time(NULL); - //printf(">>>>>>>> balances.%d done errs.%d spendind.%d\n",bp->hdrsi,errs,n); - return(-errs); -} - -void iguana_truncatebalances(struct iguana_info *coin) -{ - int32_t i; struct iguana_bundle *bp; - for (i=0; ibalanceswritten; i++) - { - if ( (bp= coin->bundles[i]) != 0 ) - { - bp->balancefinish = 0; - bp->Xvalid = 0; - iguana_volatilespurge(coin,&bp->ramchain); - } - } - coin->balanceswritten = 0; -} - -int32_t iguana_volatilesinit(struct iguana_info *coin) -{ - bits256 balancehash,allbundles; struct iguana_utxo *Uptr; struct iguana_account *Aptr; - struct sha256_vstate vstate,bstate; int32_t i,from_ro,numpkinds,numunspents; struct iguana_bundle *bp; struct iguana_block *block; - uint32_t crc,filecrc; FILE *fp; char crcfname[512],str[65],str2[65],buf[2048]; - from_ro = 1; - for (i=0; ibalanceswritten; i++) - { - if ( (bp= coin->bundles[i]) == 0 ) - break; - if ( bp->emitfinish <= 1 || (i > 0 && bp->utxofinish <= 1) ) - { - printf("hdrsi.[%d] emitfinish.%u utxofinish.%u\n",i,bp->emitfinish,bp->utxofinish); - break; - } - iguana_volatilesmap(coin,&bp->ramchain); - if ( from_ro != 0 && (bp->ramchain.from_ro == 0 || (bp->hdrsi > 0 && bp->ramchain.from_roX == 0) || bp->ramchain.from_roA == 0 || bp->ramchain.from_roU == 0) ) - { - printf("from_ro.[%d] %d %d %d %d\n",bp->hdrsi,bp->ramchain.from_ro,bp->ramchain.from_roX,bp->ramchain.from_roA,bp->ramchain.from_roU); - from_ro = 0; - } - } - if ( i < coin->balanceswritten-1 ) - { - printf("TRUNCATE balances written.%d -> %d\n",coin->balanceswritten,i); - iguana_truncatebalances(coin); - } - else - { - coin->balanceswritten = i; - //printf("verify crc and sha256 hash for %d of %d\n",i,coin->balanceswritten); - vupdate_sha256(balancehash.bytes,&vstate,0,0); - vupdate_sha256(allbundles.bytes,&bstate,0,0); - filecrc = 0; - sprintf(crcfname,"%s/%s/balancecrc.%d",GLOBAL_DBDIR,coin->symbol,coin->balanceswritten); - if ( (fp= fopen(crcfname,"rb")) != 0 ) - { - if ( fread(&filecrc,1,sizeof(filecrc),fp) != sizeof(filecrc) ) - filecrc = 0; - else if ( fread(&balancehash,1,sizeof(balancehash),fp) != sizeof(balancehash) ) - filecrc = 0; - else if ( memcmp(&balancehash,&coin->balancehash,sizeof(balancehash)) != 0 ) - filecrc = 0; - else if ( fread(&allbundles,1,sizeof(allbundles),fp) != sizeof(allbundles) ) - filecrc = 0; - else if ( memcmp(&allbundles,&coin->allbundles,sizeof(allbundles)) != 0 ) - filecrc = 0; - fclose(fp); - } - if ( filecrc != 0 ) - printf("have filecrc.%08x for %s milli.%.0f from_ro.%d\n",filecrc,bits256_str(str,balancehash),OS_milliseconds(),from_ro); - if ( from_ro == 0 || filecrc == 0 ) - { - if ( filecrc == 0 ) - { - vupdate_sha256(balancehash.bytes,&vstate,0,0); - vupdate_sha256(allbundles.bytes,&bstate,0,0); - } - for (i=crc=0; ibalanceswritten; i++) - { - numpkinds = numunspents = 0; - Aptr = 0, Uptr = 0; - if ( (bp= coin->bundles[i]) != 0 && bp->ramchain.H.data != 0 && (numpkinds= bp->ramchain.H.data->numpkinds) > 0 && (numunspents= bp->ramchain.H.data->numunspents) > 0 && (Aptr= bp->ramchain.A2) != 0 && (Uptr= bp->ramchain.Uextras) != 0 ) - { - if ( (bp->bundleheight % 10000) == 0 ) - fprintf(stderr,"."); - if ( filecrc == 0 ) - { - vupdate_sha256(balancehash.bytes,&vstate,(void *)Aptr,sizeof(*Aptr) * numpkinds); - vupdate_sha256(balancehash.bytes,&vstate,(void *)Uptr,sizeof(*Uptr) * numunspents); - vupdate_sha256(allbundles.bytes,&bstate,(void *)bp->hashes,sizeof(bp->hashes[0]) * bp->n); - } - crc = calc_crc32(crc,(void *)Aptr,(int32_t)(sizeof(*Aptr) * numpkinds)); - crc = calc_crc32(crc,(void *)Uptr,(int32_t)(sizeof(*Uptr) * numunspents)); - crc = calc_crc32(crc,(void *)bp->hashes,(int32_t)(sizeof(bp->hashes[0]) * bp->n)); - } //else printf("missing hdrs.[%d] data.%p num.(%u %d) %p %p\n",i,bp->ramchain.H.data,numpkinds,numunspents,Aptr,Uptr); - } - } else crc = filecrc; - printf("millis %.0f from_ro.%d written.%d crc.%08x/%08x balancehash.(%s) vs (%s)\n",OS_milliseconds(),from_ro,coin->balanceswritten,crc,filecrc,bits256_str(str,balancehash),bits256_str(str2,coin->balancehash)); - if ( (filecrc != 0 && filecrc != crc) || memcmp(balancehash.bytes,coin->balancehash.bytes,sizeof(balancehash)) != 0 || memcmp(allbundles.bytes,coin->allbundles.bytes,sizeof(allbundles)) != 0 ) - { - printf("balancehash or crc.(%x %x) mismatch or allbundles.(%llx %llx) mismatch\n",crc,filecrc,(long long)allbundles.txid,(long long)coin->allbundles.txid); - iguana_truncatebalances(coin); - OS_removefile(crcfname,0); - } - else - { - printf("MATCHED balancehash numhdrsi.%d crc.%08x\n",coin->balanceswritten,crc); - if ( (fp= fopen(crcfname,"wb")) != 0 ) - { - if ( fwrite(&crc,1,sizeof(crc),fp) != sizeof(crc) || fwrite(&balancehash,1,sizeof(balancehash),fp) != sizeof(balancehash) || fwrite(&allbundles,1,sizeof(allbundles),fp) != sizeof(allbundles) ) - printf("error writing.(%s)\n",crcfname); - fclose(fp); - } - else - { - printf("volatileinit: cant create.(%s)\n",crcfname); - return(-1); - } - } - } - if ( (coin->RTheight= coin->balanceswritten * coin->chain->bundlesize) > coin->longestchain ) - coin->longestchain = coin->RTheight; - iguana_bundlestats(coin,buf,IGUANA_DEFAULTLAG); - if ( (bp= coin->bundles[coin->balanceswritten-1]) != 0 && (block= bp->blocks[bp->n-1]) != 0 ) - { - //char str[65]; - //printf("set hwmchain.%d <- %s %p\n",bp->bundleheight+bp->n-1,bits256_str(str,bp->hashes[bp->n-1]),block); - if ( block->height > coin->blocks.hwmchain.height ) - coin->blocks.hwmchain = *block; - } - //printf("end volatilesinit\n"); - if ( iguana_fastfindinit(coin) == 0 )//&& coin->PREFETCHLAG >= 0 ) - iguana_fastfindcreate(coin); - return(coin->balanceswritten); -} - -void iguana_initfinal(struct iguana_info *coin,bits256 lastbundle) -{ - int32_t i; struct iguana_bundle *bp; bits256 hash2; struct iguana_block *block; char hashstr[65]; - if ( bits256_nonz(lastbundle) > 0 ) - { - init_hexbytes_noT(hashstr,lastbundle.bytes,sizeof(bits256)); - printf("req lastbundle.(%s)\n",hashstr); - queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1); - } - for (i=0; ibundlescount-1; i++) - { - if ( (bp= coin->bundles[i]) == 0 || bp->emitfinish <= 1 ) - { - printf("initfinal break.[%d]: bp.%p or emit.%u utxofinish.%u\n",i,bp,bp!=0?bp->emitfinish:-1,bp!=0?bp->utxofinish:-1); - break; - } - if ( i == 0 ) - bp->utxofinish = bp->startutxo = (uint32_t)time(NULL); - } - if ( i < coin->bundlescount-1 ) - { - printf("spendvectors.[%d] max.%d missing, will regen all of them\n",i,coin->bundlescount-1); - for (i=0; ibundlescount-1; i++) - { - if ( (bp= coin->bundles[i]) != 0 ) - bp->startutxo = bp->utxofinish = 0; - } - } - else - { - for (i=0; ibundlescount-1; i++) - { - if ( (bp= coin->bundles[i]) != 0 ) - bp->converted = (uint32_t)time(NULL); - } - } - printf("i.%d bundlescount.%d\n",i,coin->bundlescount); - if ( coin->balanceswritten > 1 ) - coin->balanceswritten = iguana_volatilesinit(coin); - if ( coin->balanceswritten > 1 ) - { - for (i=0; ibalanceswritten; i++) - { - //printf("%d ",i); - iguana_validateQ(coin,coin->bundles[i]); - } - } - printf("i.%d balanceswritten.%d\n",i,coin->balanceswritten); - if ( coin->balanceswritten < coin->bundlescount ) - { - for (i=coin->balanceswritten; ibundlescount; i++) - { - if ( (bp= coin->bundles[i]) != 0 && bp->queued == 0 ) - { - //printf("%d ",i); - iguana_bundleQ(coin,bp,1000); - } - } - printf("iguana_bundlesQ %d to %d\n",coin->balanceswritten,coin->bundlescount); - } - if ( (coin->origbalanceswritten= coin->balanceswritten) > 0 ) - iguana_volatilesinit(coin); - iguana_savehdrs(coin); - iguana_fastlink(coin,coin->balanceswritten * coin->chain->bundlesize - 1); - iguana_walkchain(coin,0); - hash2 = iguana_blockhash(coin,coin->balanceswritten * coin->chain->bundlesize); - if ( bits256_nonz(hash2) != 0 && (block= iguana_blockfind("initfinal",coin,hash2)) != 0 ) - _iguana_chainlink(coin,block); -} - -int32_t iguana_balanceflush(struct iguana_info *coin,int32_t refhdrsi) -{ - int32_t hdrsi,numpkinds,iter,numhdrsi,i,numunspents,err; struct iguana_bundle *bp; - char fname[1024],fname2[1024],destfname[1024]; bits256 balancehash,allbundles; FILE *fp,*fp2; - struct iguana_utxo *Uptr; struct iguana_account *Aptr; struct sha256_vstate vstate,bstate; - vupdate_sha256(balancehash.bytes,&vstate,0,0); - numhdrsi = refhdrsi; - vupdate_sha256(balancehash.bytes,&vstate,0,0); - vupdate_sha256(allbundles.bytes,&bstate,0,0); - for (iter=0; iter<3; iter++) - { - for (hdrsi=0; hdrsibundles[hdrsi]) != 0 && bp->ramchain.H.data != 0 && (numpkinds= bp->ramchain.H.data->numpkinds) > 0 && (numunspents= bp->ramchain.H.data->numunspents) > 0 && (Aptr= bp->ramchain.A2) != 0 && (Uptr= bp->ramchain.Uextras) != 0 ) - { - sprintf(fname,"%s/%s/debits.%d_N%d",GLOBAL_TMPDIR,coin->symbol,bp->hdrsi,numhdrsi); - sprintf(fname2,"%s/%s/lastspends.%d_N%d",GLOBAL_TMPDIR,coin->symbol,bp->hdrsi,numhdrsi); - if ( iter == 0 ) - { - vupdate_sha256(balancehash.bytes,&vstate,(void *)Aptr,sizeof(*Aptr)*numpkinds); - vupdate_sha256(balancehash.bytes,&vstate,(void *)Uptr,sizeof(*Uptr)*numunspents); - vupdate_sha256(allbundles.bytes,&bstate,(void *)bp->hashes,sizeof(bp->hashes[0])*bp->n); - } - else if ( iter == 1 ) - { - if ( (fp= fopen(fname,"wb")) != 0 && (fp2= fopen(fname2,"wb")) != 0 ) - { - err = -1; - if ( fwrite(&numhdrsi,1,sizeof(numhdrsi),fp) == sizeof(numhdrsi) && fwrite(&numhdrsi,1,sizeof(numhdrsi),fp2) == sizeof(numhdrsi) && fwrite(balancehash.bytes,1,sizeof(balancehash),fp) == sizeof(balancehash) && fwrite(balancehash.bytes,1,sizeof(balancehash),fp2) == sizeof(balancehash) && fwrite(allbundles.bytes,1,sizeof(allbundles),fp) == sizeof(allbundles) && fwrite(allbundles.bytes,1,sizeof(allbundles),fp2) == sizeof(allbundles) ) - { - if ( fwrite(Aptr,sizeof(*Aptr),numpkinds,fp) == numpkinds ) - { - if ( fwrite(Uptr,sizeof(*Uptr),numunspents,fp2) == numunspents ) - { - err = 0; - printf("[%d] of %d saved (%s) and (%s)\n",hdrsi,numhdrsi,fname,fname2); - } - } - } - if ( err != 0 ) - { - printf("balanceflush.%s error iter.%d hdrsi.%d\n",coin->symbol,iter,hdrsi); - fclose(fp); - fclose(fp2); - return(-1); - } - fclose(fp), fclose(fp2); - } - else - { - printf("error opening %s or %s %p\n",fname,fname2,fp); - if ( fp != 0 ) - fclose(fp); - } - } - else if ( iter == 2 ) - { - sprintf(destfname,"%s/%s/accounts/debits.%d",GLOBAL_DBDIR,coin->symbol,bp->bundleheight); - if ( OS_copyfile(fname,destfname,1) < 0 ) - { - printf("balances error copying (%s) -> (%s)\n",fname,destfname); - return(-1); - } - sprintf(destfname,"%s/%s/accounts/lastspends.%d",GLOBAL_DBDIR,coin->symbol,bp->bundleheight); - if ( OS_copyfile(fname2,destfname,1) < 0 ) - { - printf("balances error copying (%s) -> (%s)\n",fname2,destfname); - return(-1); - } - printf("%s -> %s\n",fname,destfname); - OS_removefile(fname,0); - OS_removefile(fname2,0); - } - if ( bp->ramchain.allocatedA2 == 0 || bp->ramchain.allocatedU2 == 0 ) - { - printf("skip saving.[%d] files as not allocated\n",bp->hdrsi); - break; - } - } - else if ( hdrsi > 0 && (coin->current == 0 || hdrsi != coin->current->hdrsi) ) - { - printf("balanceflush iter.%d error loading [%d] Aptr.%p Uptr.%p numpkinds.%u numunspents.%u\n",iter,hdrsi,Aptr,Uptr,numpkinds,numunspents); - return(-1); - } - } - } - coin->allbundles = allbundles; - coin->balancehash = balancehash; - coin->balanceswritten = numhdrsi; - if ( 1 ) - { - for (hdrsi=0; hdrsibundles[hdrsi]) == 0 && bp != coin->current ) - { - iguana_volatilespurge(coin,&bp->ramchain); - if ( iguana_volatilesmap(coin,&bp->ramchain) != 0 ) - printf("error mapping bundle.[%d]\n",hdrsi); - } - } - char str[65]; printf("BALANCES WRITTEN for %d orig.%d bundles %s\n",coin->balanceswritten,coin->origbalanceswritten,bits256_str(str,coin->balancehash)); - if ( 0 && coin->balanceswritten > coin->origbalanceswritten+10 ) // strcmp(coin->symbol,"BTC") == 0 && - { - coin->active = 0; - coin->started = 0; - for (i=0; ipeers.active[i].dead = (uint32_t)time(NULL); -#ifdef __linux__ - char cmd[1024]; - sprintf(cmd,"mksquashfs %s/%s %s.%d -comp xz",GLOBAL_DBDIR,coin->symbol,coin->symbol,coin->balanceswritten); - if ( system(cmd) != 0 ) - printf("error system(%s)\n",cmd); - else - { - sprintf(cmd,"sudo umount %s/ro/%s",GLOBAL_DBDIR,coin->symbol); - if ( system(cmd) != 0 ) - printf("error system(%s)\n",cmd); - else - { - sprintf(cmd,"sudo mount %s.%d %s/ro/%s -t squashfs -o loop",coin->symbol,coin->balanceswritten,GLOBAL_DBDIR,coin->symbol); - if ( system(cmd) != 0 ) - printf("error system(%s)\n",cmd); - } - } -#endif - for (i=0; i<30; i++) - { - printf("need to exit, please restart after shutdown in %d seconds, or just ctrl-C\n",30-i); - sleep(1); - } - exit(-1); - } - coin->balanceswritten = iguana_volatilesinit(coin); - //printf("flush free\n"); - iguana_RTramchainfree(coin,bp); - return(coin->balanceswritten); -} - -int32_t iguana_spendvectorsaves(struct iguana_info *coin) +cJSON *ramchain_unspentjson(struct iguana_unspent *up,uint32_t unspentind) { - int32_t i,j,n,iter; struct iguana_bundle *bp; - if ( coin->spendvectorsaved > 1 ) - return(0); - coin->spendvectorsaved = 1; - n = coin->bundlescount - 1; - //printf("SAVE SPEND VECTORS %d of %d\n",n,coin->bundlescount); - for (iter=0; iter<2; iter++) - { - for (i=0; ibundles[i]) != 0 ) - { - if ( iter == 0 ) - { - if ( bp->tmpspends != 0 )//bp->ramchain.Xspendinds == 0 && - { - for (j=0; jnumtmpspends; j++) - if ( bp->tmpspends[j].tmpflag != 0 ) - { - printf("vectorsave.[%d] vec.%d still has tmpflag\n",i,j); - return(-1); - } - } - } - else if ( iguana_spendvectorsave(coin,bp,&bp->ramchain,bp->tmpspends,bp->numtmpspends,bp->ramchain.H.data->numspends) == 0 ) - { - if ( bp->tmpspends != 0 && bp->numtmpspends > 0 && bp->tmpspends != bp->ramchain.Xspendinds ) - myfree(bp->tmpspends,sizeof(*bp->tmpspends) * bp->numtmpspends); - bp->numtmpspends = 0; - bp->tmpspends = 0; - } - } - } - } - coin->spendvectorsaved = (uint32_t)time(NULL); - return(0); + cJSON *item = cJSON_CreateObject(); + jaddnum(item,"hdrsi",up->hdrsi); + jaddnum(item,"pkind",up->pkind); + jaddnum(item,"unspentind",unspentind); + jaddnum(item,"prevunspentind",up->prevunspentind); + jadd64bits(item,"satoshis",up->value); + jaddnum(item,"txidind",up->txidind); + jaddnum(item,"vout",up->vout); + jaddnum(item,"type",up->type); + jaddnum(item,"fileid",up->fileid); + jaddnum(item,"scriptpos",up->scriptpos); + jaddnum(item,"scriptlen",up->scriptlen); + return(item); } -int32_t iguana_spendvectorconvs(struct iguana_info *coin,struct iguana_bundle *spentbp,int32_t starti) +cJSON *iguana_unspentjson(struct supernet_info *myinfo,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) { - struct iguana_bundle *bp; int16_t spent_hdrsi; uint32_t numpkinds; struct iguana_unspent *spentU; struct iguana_spendvector *vec; int32_t i,converted,j,n = coin->bundlescount; struct iguana_ramchain *ramchain; struct iguana_ramchaindata *rdata = 0; - if ( (rdata= spentbp->ramchain.H.data) == 0 ) + /*{ + "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_waddress *waddr; int32_t height; char scriptstr[8192],asmstr[sizeof(scriptstr)+1024]; cJSON *item; uint32_t checkind; + item = cJSON_CreateObject(); + jaddbits256(item,"txid",T[up->txidind].txid); + jaddnum(item,"vout",up->vout); + jaddstr(item,"address",coinaddr); + 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 ( (checkind= iguana_unspentindfind(coin,&height,T[up->txidind].txid,up->vout,coin->bundlescount-1)) != 0 ) { - //if ( spentbp == coin->current ) - printf("iguana_spendvectorconvs: [%d] null rdata.%p\n",spentbp->hdrsi,rdata); - return(-1); + jaddnum(item,"confirmations",coin->blocks.hwmchain.height - height + 1); + jaddnum(item,"checkind",checkind); } - spent_hdrsi = spentbp->hdrsi; - ramchain = &spentbp->ramchain; - numpkinds = rdata->numpkinds; - spentU = (void *)(long)((long)rdata + rdata->Uoffset); - for (i=converted=0; ibundles[i]) != 0 && bp->tmpspends != 0 ) - { - for (j=0; jnumtmpspends; j++) - { - vec = &bp->tmpspends[j]; - if ( vec->hdrsi == spent_hdrsi ) - { - if ( vec->tmpflag == 0 ) - { - if ( bp->tmpspends != bp->ramchain.Xspendinds && bp != coin->current ) - printf("unexpected null tmpflag [%d] j.%d spentbp.[%d]\n",bp->hdrsi,j,spentbp->hdrsi); - } - else - { - if ( _iguana_spendvectorconv(vec,&spentU[vec->unspentind],numpkinds,vec->hdrsi,vec->unspentind) != 0 ) - converted++; - else - { - printf("iguana_spendvectorconv.[%d] error [%d] at %d of T[%d/%d] [%d] u%u p%u\n",spentbp->hdrsi,bp->hdrsi,j,bp->numtmpspends,n,vec->hdrsi,vec->unspentind,spentU[vec->unspentind].pkind); - return(-1); - } - } - } - } - } - else if ( bp->hdrsi < coin->bundlescount-1 ) - { - //printf("iguana_spendvectorconvs: [%d] null bp.%p\n",i,bp); - } - } - spentbp->converted = (uint32_t)time(NULL); - //printf("spendvectorconvs.[%d] converted.%d\n",refbp->hdrsi,converted); - return(converted); + jaddstr(item,"account",wacct->account); + jadd(item,"spendable",jtrue()); + } else jadd(item,"spendable",jfalse()); + jadd(item,"unspent",ramchain_unspentjson(up,unspentind)); + return(item); } -int32_t iguana_convert(struct iguana_info *coin,int32_t helperid,struct iguana_bundle *bp,int32_t RTflag,int32_t starti) +struct iguana_pkhash *iguana_pkhashfind(struct iguana_info *coin,struct iguana_ramchain **ramchainp,int64_t *depositsp,uint32_t *lastunspentindp,struct iguana_pkhash *p,uint8_t rmd160[20],int32_t firsti,int32_t endi) { - static int64_t total[256],depth; - int32_t i,n,m,max,converted; int64_t total_tmpspends,sum; double startmillis = OS_milliseconds(); - depth++; - if ( (converted= iguana_spendvectorconvs(coin,bp,starti)) < 0 ) - { - printf("error iguana_convert.[%d]\n",bp->hdrsi); - return(0); - } - else + uint8_t *PKbits; struct iguana_pkhash *P; uint32_t pkind,numpkinds,i; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; struct iguana_ramchaindata *rdata; struct iguana_account *ACCTS; + *depositsp = 0; + *ramchainp = 0; + *lastunspentindp = 0; + for (i=firsti; ibundlescount&&i<=endi; i++) { - n = coin->bundlescount; - for (i=m=total_tmpspends=0; ibundles[i]) != 0 ) { - if ( coin->bundles[i] != 0 ) - { - total_tmpspends += coin->bundles[i]->numtmpspends; - if ( coin->bundles[i]->converted > 1 ) - m++; - } - } - max = (int32_t)(sizeof(total) / sizeof(*total)); - total[helperid % max] += converted; - for (i=sum=0; ihdrsi,OS_milliseconds()-startmillis,converted,m,n,(long long)sum,(long long)total_tmpspends,(int32_t)depth); - } - depth--; - return(converted); -} - -void iguana_RTramchainfree(struct iguana_info *coin,struct iguana_bundle *bp) -{ - int32_t hdrsi; - if ( coin->utxotable != 0 ) - { - printf("free RTramchain\n"); - iguana_utxoupdate(coin,-1,0,0,0,0,-1); // free hashtables - coin->RTheight = coin->balanceswritten * coin->chain->bundlesize; - coin->RTgenesis = 0; - iguana_ramchain_free(coin,&coin->RTramchain,1); - if ( bp != 0 ) - bp->ramchain = coin->RTramchain; - iguana_mempurge(&coin->RTmem); - iguana_mempurge(&coin->RThashmem); - coin->RTdatabad = 0; - for (hdrsi=coin->bundlescount-1; hdrsi>0; hdrsi--) - if ( (bp= coin->bundles[hdrsi]) == 0 && bp != coin->current ) + if ( 0 && coin->RTramchain_busy != 0 ) { - iguana_volatilespurge(coin,&bp->ramchain); - if ( iguana_volatilesmap(coin,&bp->ramchain) != 0 ) - printf("error mapping bundle.[%d]\n",hdrsi); + printf("iguana_pkhashfind: unexpected access when RTramchain_busy\n"); + return(0); } - printf("done RTramchain\n"); - } -} - -void *iguana_ramchainfile(struct iguana_info *coin,struct iguana_ramchain *dest,struct iguana_ramchain *R,struct iguana_bundle *bp,int32_t bundlei,struct iguana_block *block) -{ - char fname[1024]; long filesize; int32_t err; void *ptr=0; - if ( block == bp->blocks[bundlei] && (ptr= iguana_bundlefile(coin,fname,&filesize,bp,bundlei)) != 0 ) - { - if ( iguana_mapchaininit(fname,coin,R,bp,bundlei,block,ptr,filesize) >= 0 ) - { - if ( dest != 0 && dest->H.data != 0 ) - err = iguana_ramchain_iterate(coin,dest,R,bp,bundlei); - else err = 0; - if ( err != 0 || dest->H.data == 0 || bits256_cmp(R->H.data->firsthash2,block->RO.hash2) != 0 ) + ramchain = (bp != coin->current) ? &bp->ramchain : &coin->RTramchain; + if ( (rdata= ramchain->H.data) != 0 ) { - char str[65]; - printf("ERROR [%d:%d] %s vs ",bp->hdrsi,bundlei,bits256_str(str,block->RO.hash2)); - printf("mapped.%s\n",bits256_str(str,R->H.data->firsthash2)); - } else return(ptr); - } - iguana_blockunmark(coin,block,bp,bundlei,1); - iguana_ramchain_free(coin,R,1); - } //else printf("ramchainfile ptr.%p block.%p\n",ptr,block); - return(0); -} - -void iguana_RTramchainalloc(char *fname,struct iguana_info *coin,struct iguana_bundle *bp) -{ - uint32_t i,changed = 0; struct iguana_ramchaindata *rdata; struct iguana_ramchain *dest = &coin->RTramchain; struct iguana_blockRO *B; struct iguana_bundle *tmpbp; - if ( (rdata= dest->H.data) != 0 ) - { - i = 0; - if ( coin->RTheight != bp->bundleheight + rdata->numblocks ) - changed++; - else - { - B = (void *)(long)((long)rdata + rdata->Boffset); - for (i=0; inumblocks; i++) - if ( bits256_cmp(B[i].hash2,bp->hashes[i]) != 0 ) - { - char str[65],str2[65]; printf("mismatched hash2 at %d %s vs %s\n",bp->bundleheight+i,bits256_str(str,B[i].hash2),bits256_str(str2,bp->hashes[i])); - changed++; - break; - } - } - if ( changed != 0 ) - { - printf("RTramchain changed %d bundlei.%d | coin->RTheight %d != %d bp->bundleheight + %d coin->RTramchain.H.data->numblocks\n",coin->RTheight,i,coin->RTheight,bp->bundleheight,rdata->numblocks); - //coin->RTheight = coin->balanceswritten * coin->chain->bundlesize; - iguana_RTramchainfree(coin,bp); - } - } - if ( coin->RTramchain.H.data == 0 ) - { - printf("ALLOC RTramchain\n"); - iguana_ramchainopen(fname,coin,dest,&coin->RTmem,&coin->RThashmem,bp->bundleheight,bp->hashes[0]); - dest->H.txidind = dest->H.unspentind = dest->H.spendind = dest->pkind = dest->H.data->firsti; - dest->externalind = dest->H.stacksize = 0; - dest->H.scriptoffset = 1; - if ( 1 ) - { - for (i=0; ihdrsi; i++) - if ( (tmpbp= coin->bundles[i]) != 0 ) + numpkinds = rdata->numpkinds; + PKbits = (void *)(long)((long)rdata + rdata->PKoffset); + P = (void *)(long)((long)rdata + rdata->Poffset); + if ( bp == coin->current ) + ACCTS = ramchain->A; + else ACCTS = (void *)(long)((long)rdata + rdata->Aoffset); + if ( (pkind= iguana_sparseaddpk(PKbits,rdata->pksparsebits,rdata->numpksparse,rmd160,P,0,ramchain)) > 0 && pkind < numpkinds ) { - //iguana_volatilespurge(coin,&tmpbp->ramchain); - iguana_volatilesmap(coin,&tmpbp->ramchain); + *ramchainp = ramchain; + *depositsp = ACCTS[pkind].total; + *lastunspentindp = ACCTS[pkind].lastunspentind; + *p = P[pkind]; + printf("[%d] return pkind.%u %.8f last.%u ACCTS.%p %p\n",i,pkind,dstr(*depositsp),*lastunspentindp,ACCTS,ramchain->A); + return(p); } - sleep(1); + else if ( pkind != 0 ) + printf("[%d] not found pkind.%d vs num.%d RT.%d rdata.%p\n",i,pkind,rdata->numpkinds,bp->isRT,rdata); + } else printf("%s.[%d] error null rdata isRT.%d\n",coin->symbol,i,bp->isRT); } } + return(0); } -void iguana_rdataset(struct iguana_ramchain *dest,struct iguana_ramchaindata *rdest,struct iguana_ramchain *src) -{ - *dest = *src; - dest->H.data = rdest; - *rdest = *src->H.data; - rdest->numpkinds = src->pkind; - rdest->numexternaltxids = src->externalind; - rdest->numtxids = src->H.txidind; - rdest->numunspents = src->H.unspentind; - rdest->numspends = src->H.spendind; - //printf("RT set numtxids.%u numspends.%u\n",rdest->numtxids,rdest->numspends); -} - -void iguana_rdatarestore(struct iguana_ramchain *dest,struct iguana_ramchaindata *rdest,struct iguana_ramchain *src) +int32_t iguana_uheight(struct iguana_info *coin,int32_t bundleheight,struct iguana_txid *T,int32_t numtxids,struct iguana_unspent *up) { - *src = *dest; - *src->H.data = *rdest; - src->pkind = rdest->numpkinds; - src->externalind = rdest->numexternaltxids; - src->H.txidind = rdest->numtxids; - src->H.unspentind = rdest->numunspents; - src->H.spendind = rdest->numspends; - printf("RT restore numtxids.%u numspends.%u\n",rdest->numtxids,rdest->numspends); + if ( up->txidind > 0 && up->txidind < numtxids ) + return(bundleheight + T[up->txidind].bundlei); + else return(bundleheight); } -void iguana_RThdrs(struct iguana_info *coin,struct iguana_bundle *bp,int32_t numaddrs) +int64_t iguana_pkhashbalance(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int64_t *spentp,uint64_t *unspents,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,int32_t lastheight,int32_t minconf,int32_t maxconf) { - int32_t datalen,i; uint8_t serialized[512]; char str[65]; struct iguana_peer *addr; - for (i=0; ipeers.numranked; i++) + struct iguana_unspent *U; struct iguana_utxo *U2; struct iguana_spend *S; int32_t max,uheight,spentheight; uint32_t pkind=0,unspentind; int64_t spent = 0,checkval,deposits = 0; struct iguana_txid *T; struct iguana_account *A2; struct iguana_ramchaindata *rdata = 0; int64_t RTspend = 0; + max = *nump; + *spentp = *nump = 0; + if ( 0 && coin->RTramchain_busy != 0 ) { - queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(bits256_str(str,bp->hashes[0])),1); - if ( (addr= coin->peers.ranked[i]) != 0 && addr->usock >= 0 && addr->dead == 0 && (datalen= iguana_gethdrs(coin,serialized,coin->chain->gethdrsmsg,bits256_str(str,bp->hashes[0]))) > 0 ) - { - iguana_send(coin,addr,serialized,datalen); - addr->pendhdrs++; - } + printf("iguana_pkhashbalance: unexpected access when RTramchain_busy\n"); + return(0); } -} - -void iguana_RTspendvectors(struct iguana_info *coin,struct iguana_bundle *bp) -{ - int32_t iterate,lasti,num,hdrsi,orignumemit; struct iguana_ramchain R; struct iguana_ramchaindata RDATA; - if ( bp->hdrsi <= 0 ) - return; - bp->ramchain = coin->RTramchain; - iguana_rdataset(&R,&RDATA,&coin->RTramchain); - if ( (lasti= (coin->RTheight - ((coin->RTheight/bp->n)*bp->n))) >= bp->n-1 ) - lasti = bp->n - 1; - orignumemit = bp->numtmpspends; -#ifdef __APPLE__ - iterate = 0*(coin->bundlescount-1); -#else - iterate = 0; -#endif - if ( iguana_spendvectors(coin,bp,&coin->RTramchain,coin->RTstarti,lasti,0,iterate) < 0 ) + if ( ramchain->Uextras == 0 || (rdata= ramchain->H.data) == 0 ) { - printf("RTutxo error -> RTramchainfree\n"); - coin->RTdatabad = 1; - return; + printf("iguana_pkhashbalance: unexpected null spents.%p or rdata.%p\n",ramchain->Uextras,rdata); + return(0); } - else + unspentind = lastunspentind; + U = (void *)(long)((long)rdata + rdata->Uoffset); + T = (void *)(long)((long)rdata + rdata->Toffset); + RTspend = 0; + if ( lastheight == 0 ) + lastheight = IGUANA_MAXHEIGHT; + while ( unspentind > 0 ) { - printf("RTspendvectors calculated to %d [%d]\n",coin->RTheight,bp->hdrsi); - bp->converted = 1; - for (hdrsi=num=0; hdrsihdrsi; hdrsi++) + uheight = iguana_uheight(coin,ramchain->height,T,rdata->numtxids,&U[unspentind]); + if ( uheight < lastheight ) { -#ifdef __APPLE__ - if ( coin->bundles[hdrsi]->lastprefetch == 0 ) + deposits += U[unspentind].value; + if ( lastheight < 0 || iguana_spentflag(coin,&RTspend,&spentheight,ramchain,hdrsi,unspentind,lastheight,minconf,maxconf,U[unspentind].value) == 0 ) { - iguana_ramchain_prefetch(coin,&coin->bundles[hdrsi]->ramchain,2); - coin->bundles[hdrsi]->lastprefetch = (uint32_t)time(NULL); - } -#endif - num += iguana_convert(coin,IGUANA_NUMHELPERS,coin->bundles[hdrsi],1,orignumemit); - } - printf("RTspendvectors converted.%d to %d\n",num,coin->RTheight); - bp->converted = (uint32_t)time(NULL); - if ( iguana_balancegen(coin,1,bp,coin->RTstarti,coin->RTheight > 0 ? coin->RTheight-1 : bp->n-1,orignumemit) < 0 ) - coin->RTdatabad = 1; - else if ( coin->RTgenesis == 0 ) - printf(">>>>>> IGUANA BTC INITIALIZATION COMPLETE <<<<<<\n"); - //printf("iguana_balancegen [%d] (%d to %d)\n",bp->hdrsi,coin->RTstarti,(coin->RTheight-1)%bp->n); - coin->RTstarti = (coin->RTheight % bp->n); - } -} - -int32_t iguana_realtime_update(struct iguana_info *coin) -{ - double startmillis0; static double totalmillis0; static int32_t num0; - struct iguana_bundle *bp; struct iguana_ramchaindata *rdata; int32_t bundlei,i,n,flag=0; bits256 hash2,*ptr; struct iguana_peer *addr; - struct iguana_block *block=0; struct iguana_blockRO *B; struct iguana_ramchain *dest=0,blockR; - if ( coin->current != 0 && (coin->blocks.hwmchain.height % coin->chain->bundlesize) == coin->chain->bundlesize-1 ) - { - block = coin->current->blocks[coin->current->n - 1]; - if ( _iguana_chainlink(coin,block) <= 0 ) - { - //printf("RT edge case couldnt link\n"); + if ( *nump < max && unspents != 0 ) + unspents[*nump] = ((uint64_t)hdrsi << 32) | unspentind; + (*nump)++; + if ( array != 0 ) + jaddi(array,iguana_unspentjson(myinfo,coin,hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33)); + } else spent += U[unspentind].value; + if ( p->pkind != U[unspentind].pkind ) + printf("warning: [%d] p->pkind.%u vs U->pkind.%u for u%d\n",hdrsi,p->pkind,U[unspentind].pkind,unspentind); } - else printf("RT edge case.%d\n",block->height); + pkind = p->pkind; + unspentind = U[unspentind].prevunspentind; } - if ( coin->spendvectorsaved <= 1 ) - return(0); - for (i=0; ibundlescount-1; i++) + if ( lastheight > 0 && (A2= ramchain->A2) != 0 && (U2= ramchain->Uextras) != 0 ) { - if ( (bp= coin->bundles[i]) != 0 && (i > 0 && bp->utxofinish == 0) ) + S = (void *)(long)((long)rdata + rdata->Soffset); + unspentind = A2[pkind].lastunspentind; + checkval = 0; + while ( unspentind > 0 ) { - if ( iguana_spendvectors(coin,bp,&bp->ramchain,0,bp->n,0,0) < 0 ) + uheight = iguana_uheight(coin,ramchain->height,T,rdata->numtxids,&U[unspentind]); + if ( uheight < lastheight ) { - printf("error generating spendvectors.[%d], exiting. just restart iguana\n",i); - exit(-1); - } // else printf("generated UTXO.[%d]\n",i); - coin->spendvectorsaved = 1; + checkval += U[unspentind].value; + //printf("u%u %.8f spentflag.%d prev.%u fromheight.%d\n",unspentind,dstr(U[unspentind].value),U2[unspentind].spentflag,U2[unspentind].prevunspentind,U2[unspentind].fromheight); + } + unspentind = U2[unspentind].prevunspentind; } + if ( fabs(spent - checkval - RTspend) > SMALLVAL ) + printf("spend %s: [%d] deposits %.8f spent %.8f check %.8f (%.8f) vs A2[%u] %.8f\n",lastheight==IGUANA_MAXHEIGHT?"checkerr":"",hdrsi,dstr(deposits),dstr(spent),dstr(checkval)+dstr(RTspend),dstr(*spentp),pkind,dstr(A2[pkind].total)); } - bp = coin->current; - if ( bp == 0 || iguana_validated(coin) < bp->hdrsi ) - return(0); - if ( 1 && coin->RTheight > 0 && coin->spendvectorsaved != 1 && coin->bundlescount-1 != coin->balanceswritten ) + (*spentp) = spent; + //printf("spent %.8f, RTspent %.8f deposits %.8f\n",dstr(spent),dstr(RTspend),dstr(deposits)); + return(deposits - spent); +} + +int32_t iguana_pkhasharray(struct supernet_info *myinfo,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 lastheight,uint64_t *unspents,int32_t *numunspentsp) +{ + int32_t i,n,m,maxunspents,numunspents = 0; int64_t spent,deposits,netbalance,total; uint32_t lastunspentind; struct iguana_pkhash *p,_p; struct iguana_ramchain *ramchain; struct iguana_bundle *bp; + if ( numunspentsp != 0 ) + maxunspents = *numunspentsp, *numunspentsp = 0; + else maxunspents = 0; + if ( 0 && coin->RTramchain_busy != 0 ) { - printf("RT mismatch %d != %d\n",coin->bundlescount-1,coin->balanceswritten); - coin->spendvectorsaved = 0; - iguana_RTramchainfree(coin,coin->current); - return(0); + printf("iguana_pkhasharray: unexpected access when RTramchain_busy\n"); + return(-1); } - if ( coin->RTdatabad == 0 && bp->hdrsi == coin->longestchain/coin->chain->bundlesize && bp->hdrsi >= coin->balanceswritten && coin->RTheight >= bp->bundleheight && coin->RTheight < bp->bundleheight+bp->n && ((coin->RTheight <= coin->blocks.hwmchain.height && time(NULL) > bp->lastRT) || time(NULL) > bp->lastRT+10) ) + if ( lastheight == 0 ) + lastheight = IGUANA_MAXHEIGHT; + if ( max > coin->bundlescount ) + max = coin->bundlescount; + for (total=n=0,i=max-1; i>=0; i--) { - if ( (block= bp->blocks[0]) == 0 || block->txvalid == 0 || block->mainchain == 0 ) + if ( (bp= coin->bundles[i]) == 0 ) + continue; + if ( lastheight > 0 && bp->bundleheight > lastheight ) + break; + if ( (coin->blocks.hwmchain.height - (bp->bundleheight + bp->n - 1)) > maxconf ) + continue; + if ( (coin->blocks.hwmchain.height - bp->bundleheight) < minconf ) + break; + if ( iguana_pkhashfind(coin,&ramchain,&deposits,&lastunspentind,&P[n],rmd160,i,i) != 0 ) { - if ( block != 0 ) + m = maxunspents; + p = (P == 0) ? &_p : &P[n]; + if ( (netbalance= iguana_pkhashbalance(myinfo,coin,array,&spent,unspents != 0 ? &unspents[numunspents] : 0,&m,ramchain,p,lastunspentind,rmd160,coinaddr,pubkey33,i,lastheight,minconf,maxconf)) != deposits-spent && lastheight == IGUANA_MAXHEIGHT && minconf == 1 && maxconf > coin->blocks.hwmchain.height ) { - if ( _iguana_chainlink(coin,block) <= 0 ) - { - iguana_blockunmark(coin,block,bp,0,0); - bp->issued[0] = 0; - hash2 = bp->hashes[0]; - //char str[65]; printf("RT[0] [%d:%d] %s %p\n",bp->hdrsi,0,bits256_str(str,hash2),block); - addr = coin->peers.ranked[rand() % 8]; - if ( addr != 0 && addr->usock >= 0 && addr->dead == 0 ) - iguana_sendblockreqPT(coin,addr,bp,0,hash2,0); - } + printf("pkhash balance mismatch from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",m,dstr(netbalance),dstr(deposits),dstr(spent),dstr(deposits)-dstr(spent)); } - } - //char str[65]; printf("check longest.%d RTheight.%d hwm.%d %s %p\n",coin->longestchain,coin->RTheight,coin->blocks.hwmchain.height,bits256_str(str,bp->hashes[0]),block); - if ( bits256_cmp(coin->RThash1,bp->hashes[1]) != 0 ) - coin->RThash1 = bp->hashes[1]; - bp->lastRT = (uint32_t)time(NULL); - if ( coin->RTheight < coin->longestchain && coin->peers.numranked > 0 && time(NULL) > coin->RThdrstime+10 ) - { - iguana_RThdrs(coin,bp,coin->peers.numranked); - coin->RThdrstime = bp->lastRT; - for (i=0; ipeers.numranked; i++) + else { - if ( (addr= coin->peers.ranked[i]) != 0 && addr->usock >= 0 && addr->dead == 0 ) - { - //printf("%d ",addr->numRThashes); - } + //printf("pkhash balance.[%d] from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",i,m,dstr(netbalance),dstr(deposits),dstr(spent),dstr(deposits)-dstr(spent)); + total += netbalance; + n++; } - //printf("RTheaders %s\n",coin->symbol); - } - bp->lastRT = (uint32_t)time(NULL); - iguana_RTramchainalloc("RTbundle",coin,bp); - bp->isRT = 1; - while ( (rdata= coin->RTramchain.H.data) != 0 && coin->RTheight <= coin->blocks.hwmchain.height ) - { - if ( coin->RTdatabad != 0 ) - break; - dest = &coin->RTramchain; - B = (void *)(long)((long)rdata + rdata->Boffset); - bundlei = (coin->RTheight % coin->chain->bundlesize); - if ( (block= iguana_bundleblock(coin,&hash2,bp,bundlei)) != 0 ) - iguana_bundlehashadd(coin,bp,bundlei,block); - //printf("RT.%d vs hwm.%d starti.%d bp->n %d block.%p/%p ramchain.%p\n",coin->RTheight,coin->blocks.hwmchain.height,coin->RTstarti,bp->n,block,bp->blocks[bundlei],dest->H.data); - if ( coin->RTdatabad == 0 && block != 0 && bits256_nonz(block->RO.prev_block) != 0 ) - { - iguana_blocksetcounters(coin,block,dest); - startmillis0 = OS_milliseconds(); - if ( coin->RTdatabad == 0 && iguana_ramchainfile(coin,dest,&blockR,bp,bundlei,block) == 0 ) - { - for (i=0; in; i++) - if ( GETBIT(bp->haveblock,i) == 0 ) - bp->issued[i] = 0; - if ( (n= iguana_bundleissuemissing(coin,bp,3,1.)) > 0 ) - printf("RT issued %d priority requests [%d] to unstick stuckiters.%d\n",n,bp->hdrsi,coin->stuckiters); - for (i=bundlei; in; i++) - { - block = iguana_bundleblock(coin,&hash2,bp,i); - if ( bits256_nonz(hash2) != 0 && (block == 0 || block->txvalid == 0) ) - { - uint8_t serialized[512]; int32_t len; struct iguana_peer *addr; - //char str[65]; printf("RT error [%d:%d] %s %p\n",bp->hdrsi,i,bits256_str(str,hash2),block); - addr = coin->peers.ranked[rand() % 8]; - if ( addr != 0 && addr->usock >= 0 && addr->dead == 0 && (len= iguana_getdata(coin,serialized,MSG_BLOCK,&hash2,1)) > 0 ) - iguana_send(coin,addr,serialized,len); - coin->RTgenesis = 0; - } - if ( bits256_nonz(hash2) != 0 ) - iguana_blockQ("RTerr",coin,bp,i,hash2,1); - break; - } - return(-1); - } else iguana_ramchain_free(coin,&blockR,1); - B[bundlei] = block->RO; - totalmillis0 += (OS_milliseconds() - startmillis0); - num0++; - flag++; - coin->blocks.RO[bp->bundleheight+bundlei] = block->RO; - coin->RTheight++; - printf(">>>> RT.%d hwm.%d L.%d T.%d U.%d S.%d P.%d X.%d -> size.%ld\n",coin->RTheight,coin->blocks.hwmchain.height,coin->longestchain,dest->H.txidind,dest->H.unspentind,dest->H.spendind,dest->pkind,dest->externalind,(long)dest->H.data->allocsize); - if ( coin->RTramchain.H.data != 0 ) - coin->RTramchain.H.data->numblocks = bundlei + 1; - else break; - } else break; + maxunspents -= m; + numunspents += m; } + //printf("%d: balance %.8f, lastunspent.%u\n",i,dstr(balance),lastunspentind); } - n = 0; - if ( coin->RTdatabad == 0 && dest != 0 && flag != 0 && coin->RTheight >= coin->longestchain ) + //printf("n.%d max.%d\n",n,max); + if ( numunspentsp != 0 ) + *numunspentsp = numunspents; + *totalp += total; + return(n); +} + +int64_t iguana_unspents(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *array,int32_t minconf,int32_t maxconf,uint8_t *rmdarray,int32_t numrmds,int32_t lastheight,uint64_t *unspents,int32_t *numunspentsp) +{ + int64_t total=0,sum=0; struct iguana_pkhash *P; uint8_t *addrtypes,*pubkeys; int32_t i,flag = 0; char coinaddr[64]; + if ( 0 && coin->RTramchain_busy != 0 ) { - //printf("ramchainiterate.[%d] ave %.2f micros, total %.2f seconds starti.%d num.%d\n",num0,(totalmillis0*1000.)/num0,totalmillis0/1000.,coin->RTstarti,coin->RTheight%bp->n); - if ( (n= iguana_walkchain(coin,1)) == coin->RTheight-1 ) - { - //printf("RTgenesis verified\n"); - iguana_RTspendvectors(coin,bp); - coin->RTgenesis = (uint32_t)time(NULL); - } else coin->RTdatabad = 1; + printf("iguana_pkhasharray: unexpected access when RTramchain_busy\n"); + return(sum); } - if ( dest != 0 && flag != 0 ) - printf("<<<< flag.%d RT.%d:%d hwm.%d L.%d T.%d U.%d S.%d P.%d X.%d -> size.%ld\n",flag,coin->RTheight,n,coin->blocks.hwmchain.height,coin->longestchain,dest->H.txidind,dest->H.unspentind,dest->H.spendind,dest->pkind,dest->externalind,dest->H.data!=0?(long)dest->H.data->allocsize:-1); - if ( coin->RTdatabad != 0 ) + if ( rmdarray == 0 ) + rmdarray = iguana_walletrmds(myinfo,coin,&numrmds), flag++; + if ( numrmds > 0 && rmdarray != 0 ) { - iguana_RTramchainfree(coin,bp); - //memset(bp->hashes,0,sizeof(bp->hashes)); - memset(bp->blocks,0,sizeof(bp->blocks)); - if ( 0 && bp->speculative != 0 ) + addrtypes = &rmdarray[numrmds * 20], pubkeys = &rmdarray[numrmds * 21]; + P = calloc(coin->bundlescount,sizeof(*P)); + for (i=0; ispeculative; - bp->speculative = 0; - memset(ptr,0,sizeof(*bp->speculative)*bp->n); - myfree(ptr,(bp->n+1)*sizeof(*bp->speculative)); + bitcoin_address(coinaddr,addrtypes[i],&rmdarray[i * 20],20); + iguana_pkhasharray(myinfo,coin,array,minconf,maxconf,&total,P,coin->bundlescount,&rmdarray[i * 20],coinaddr,&pubkeys[33*i],lastheight,unspents,numunspentsp); + printf("i.%d of %d: %s %.8f\n",i,numrmds,coinaddr,dstr(total)); + sum += total; } - iguana_RTramchainalloc("RTbundle",coin,bp); + printf("sum %.8f\n",dstr(sum)); + free(P); } - return(flag); + if ( flag != 0 && rmdarray != 0 ) + free(rmdarray); + return(sum); } -int32_t iguana_bundlevalidate(struct iguana_info *coin,struct iguana_bundle *bp,int32_t forceflag) +uint8_t *iguana_rmdarray(struct iguana_info *coin,int32_t *numrmdsp,cJSON *array,int32_t firsti) { - static int32_t totalerrs,totalvalidated; - FILE *fp; char fname[1024]; uint8_t *blockspace; uint32_t now = (uint32_t)time(NULL); - int32_t i,max,len,errs = 0; struct sha256_vstate vstate; bits256 validatehash; int64_t total = 0; - if ( (coin->VALIDATENODE == 0 && coin->RELAYNODE == 0) || bp->ramchain.from_ro != 0 || bp == coin->current ) - { - bp->validated = (uint32_t)time(NULL); - return(bp->n); - } - if ( bp->validated <= 1 || forceflag != 0 ) + int32_t i,n,j=0; char *coinaddr,rmdstr[41]; uint8_t *addrtypes,*rmdarray = 0; + *numrmdsp = 0; + if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) { - //printf("validate.[%d]\n",bp->hdrsi); - vupdate_sha256(validatehash.bytes,&vstate,0,0); - sprintf(fname,"%s/%s/validated/%d",GLOBAL_DBDIR,coin->symbol,bp->bundleheight); - //printf("validatefname.(%s)\n",fname); - if ( (fp= fopen(fname,"rb")) != 0 ) - { - if ( forceflag == 0 ) - { - if ( fread(&bp->validated,1,sizeof(bp->validated),fp) != sizeof(bp->validated) ||fread(&total,1,sizeof(total),fp) != sizeof(total) || fread(&validatehash,1,sizeof(validatehash),fp) != sizeof(validatehash) ) - { - printf("error reading.(%s)\n",fname); - total = bp->validated = 0; - } //else printf("(%s) total.%d validated.%u\n",fname,(int32_t)total,bp->validated); - } else OS_removefile(fname,1); - fclose(fp); - } - if ( forceflag != 0 || bp->validated <= 1 ) - { - max = sizeof(coin->blockspace); - blockspace = calloc(1,max); - iguana_volatilesmap(coin,&bp->ramchain); - for (i=0; in; i++) - { - if ( (len= iguana_peerblockrequest(coin,blockspace,max,0,bp->hashes[i],1)) < 0 ) - { - errs++; - iguana_blockunmark(coin,bp->blocks[i],bp,i,1); - totalerrs++; - } - else - { - vupdate_sha256(validatehash.bytes,&vstate,bp->hashes[i].bytes,sizeof(bp->hashes[i])); - total += len, totalvalidated++; - } - } - free(blockspace); - bp->validated = (uint32_t)time(NULL); - printf("VALIDATED.[%d] ht.%d duration.%d errs.%d total.%lld %u | total errs.%d validated.%d %llx\n",bp->hdrsi,bp->bundleheight,bp->validated - now,errs,(long long)total,bp->validated,totalerrs,totalvalidated,(long long)validatehash.txid); - } - if ( errs == 0 && fp == 0 ) + *numrmdsp = n - firsti; + rmdarray = calloc(1,(n-firsti) * (21 + 33)); + addrtypes = &rmdarray[(n-firsti) * 20]; + for (i=firsti; ivalidated,1,sizeof(bp->validated),fp) != sizeof(bp->validated) || fwrite(&total,1,sizeof(total),fp) != sizeof(total) || fwrite(&validatehash,1,sizeof(validatehash),fp) != sizeof(validatehash) ) - printf("error saving.(%s) total.%lld\n",fname,(long long)total); - fclose(fp); + bitcoin_addr2rmd160(&addrtypes[j],&rmdarray[20 * j],coinaddr); + init_hexbytes_noT(rmdstr,&rmdarray[20 * j],20); + printf("(%s %s) ",coinaddr,rmdstr); + j++; } } - bp->validatehash = validatehash; - } // else printf("skip validate.[%d] validated.%u force.%d\n",bp->hdrsi,bp->validated,forceflag); - if ( errs != 0 ) - { - printf("remove.[%d]\n",bp->hdrsi); - iguana_bundleremove(coin,bp->hdrsi,0); + printf("rmdarray[%d]\n",n); } - return(bp->n - errs); -} - -#include "../includes/iguana_apidefs.h" -#include "../includes/iguana_apideclares.h" - -STRING_ARG(iguana,initfastfind,activecoin) -{ - if ( (coin= iguana_coinfind(activecoin)) != 0 ) - { - iguana_fastfindcreate(coin); - return(clonestr("{\"result\":\"fast find initialized\"}")); - } else return(clonestr("{\"error\":\"no coin to initialize\"}")); + return(rmdarray); } -TWO_STRINGS_AND_TWO_DOUBLES(iguana,balance,activecoin,address,lastheightd,minconfd) +int64_t iguana_unspentset(struct supernet_info *myinfo,struct iguana_info *coin) { - int32_t lastheight,minconf,maxconf=SATOSHIDEN; int64_t total; uint8_t rmd160[20],pubkey33[33],addrtype; - struct iguana_pkhash *P; cJSON *array,*retjson = cJSON_CreateObject(); - if ( activecoin != 0 && activecoin[0] != 0 ) - coin = iguana_coinfind(activecoin); - if ( coin != 0 ) + int64_t sum = 0,total; struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; int32_t numunspents; + HASH_ITER(hh,myinfo->wallet,wacct,tmp) { - if ( (minconf= minconfd) <= 0 ) - minconf = 1; - lastheight = lastheightd; - jaddstr(retjson,"address",address); - if ( bitcoin_validaddress(coin,address) < 0 ) - { - jaddstr(retjson,"error","illegal address"); - return(jprint(retjson,1)); - } - if ( bitcoin_addr2rmd160(&addrtype,rmd160,address) < 0 ) + HASH_ITER(hh,wacct->waddr,waddr,tmp2) { - jaddstr(retjson,"error","cant convert address"); - return(jprint(retjson,1)); + if ( waddr->addrtype != coin->chain->pubtype || (bits256_nonz(waddr->privkey) == 0 && waddr->scriptlen == 0) ) + continue; + total = 0; + numunspents = (int32_t)(sizeof(coin->blockspace)/sizeof(*waddr->unspents)); + iguana_pkhasharray(myinfo,coin,0,coin->minconfirms,coin->longestchain,&total,0,coin->bundlescount,waddr->rmd160,waddr->coinaddr,waddr->pubkey,coin->blocks.hwmchain.height - coin->minconfirms,(uint64_t *)coin->blockspace,&numunspents); + if ( numunspents > 0 ) + { + if ( waddr->unspents == 0 || waddr->maxunspents < numunspents ) + { + waddr->unspents = realloc(waddr->unspents,sizeof(*waddr->unspents) * numunspents); + waddr->maxunspents = numunspents; + } + memcpy(waddr->unspents,coin->blockspace,sizeof(*waddr->unspents) * numunspents); + waddr->numunspents = numunspents; + waddr->balance = total; + sum += total; + } } - memset(pubkey33,0,sizeof(pubkey33)); - P = calloc(coin->bundlescount,sizeof(*P)); - array = cJSON_CreateArray(); - printf("Start %s balance.(%s) height.%d\n",coin->symbol,address,lastheight); - if ( lastheight == 0 ) - lastheight = IGUANA_MAXHEIGHT; - iguana_pkhasharray(myinfo,coin,array,minconf,maxconf,&total,P,coin->bundlescount,rmd160,address,pubkey33,lastheight); - free(P); - jadd(retjson,"unspents",array); - jaddnum(retjson,"balance",dstr(total)); - if ( lastheight > 0 ) - jaddnum(retjson,"lastheight",lastheight); } - return(jprint(retjson,1)); + return(sum); } -int64_t iguana_addressreceived(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *json,char *remoteaddr,cJSON *txids,cJSON *vouts,char *coinaddr,int32_t minconf) +int32_t iguana_unspentslists(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waddress **waddrs,int32_t maxwaddrs,int64_t required,int32_t minconf,char *account) { - int64_t balance = 0; cJSON *unspentsjson,*balancejson,*item; int32_t i,n; char *balancestr; - if ( (balancestr= iguana_balance(IGUANA_CALLARGS,coin->symbol,coinaddr,-1,minconf)) != 0 ) + int64_t remains; int32_t num = 0; struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; + remains = required * 1.1; + HASH_ITER(hh,myinfo->wallet,wacct,tmp) { - if ( (balancejson= cJSON_Parse(balancestr)) != 0 ) + if ( account != 0 && strcmp(account,wacct->account) != 0 ) + continue; + HASH_ITER(hh,wacct->waddr,waddr,tmp2) { - balance = jdouble(balancejson,"balance") * SATOSHIDEN; - if ( (txids != 0 || vouts != 0) && (unspentsjson= jarray(&n,balancejson,"unspents")) != 0 ) + if ( waddr->addrtype != coin->chain->pubtype || (bits256_nonz(waddr->privkey) == 0 && waddr->scriptlen == 0) ) + continue; + if ( waddr->balance > 0 ) { - for (i=0; ibalance; + waddrs[num++] = waddr; + if ( num >= maxwaddrs || remains <= 0 ) + break; } - free_json(balancejson); } - free(balancestr); + if ( num >= maxwaddrs || remains <= 0 ) + break; } - return(balance); + return(num); } -#include "../includes/iguana_apiundefs.h" + diff --git a/iguana/iguana_volatiles.c b/iguana/iguana_volatiles.c new file mode 100755 index 000000000..389970307 --- /dev/null +++ b/iguana/iguana_volatiles.c @@ -0,0 +1,342 @@ +/****************************************************************************** + * 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" + +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); +} + +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) +{ + //static struct iguana_hhutxo *HHUTXO; static struct iguana_hhaccount *HHACCT; static uint32_t numHHUTXO,maxHHUTXO,numHHACCT,maxHHACCT; + 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) + { + //HASH_DEL(coin->utxotable,hhutxo); + hhutxo->u.spentflag = 0; + hhutxo->u.fromheight = 0; + hhutxo->u.prevunspentind = 0; + //free(hhutxo); + } + //coin->utxotable = 0; + } + if ( coin->accountstable != 0 ) + { + HASH_ITER(hh,coin->accountstable,hhacct,tmpacct) + { + //HASH_DEL(coin->accountstable,hhacct); + hhacct->a.lastunspentind = 0; + hhacct->a.total = 0; + //free(hhacct); + } + //coin->accountstable = 0; + } + /*if ( HHUTXO != 0 ) + { + free(HHUTXO); + maxHHUTXO = numHHUTXO = 0; + HHUTXO = 0; + } + if ( HHACCT != 0 ) + { + free(HHACCT); + maxHHACCT = numHHACCT = 0; + HHACCT = 0; + }*/ + 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 && hhutxo->u.spentflag != 0 ) + { + printf("hhutxo.%p spentflag.%d\n",hhutxo,hhutxo->u.spentflag); + return(-1); + } + /*if ( 0 && numHHUTXO+1 >= maxHHUTXO ) + { + maxHHUTXO += 1; + HHUTXO = realloc(HHUTXO,sizeof(*HHUTXO) * maxHHUTXO); + }*/ + hhutxo = calloc(1,sizeof(*hhutxo));//&HHUTXO[numHHUTXO++], memset(hhutxo,0,sizeof(*hhutxo)); + hhutxo->uval = uval; + HASH_ADD_KEYPTR(hh,coin->utxotable,&hhutxo->uval,sizeof(hhutxo->uval),hhutxo); + if ( (hhacct= iguana_hhaccountfind(coin,pval)) == 0 ) + { + /*if ( 0 && numHHACCT+1 >= maxHHACCT ) + { + maxHHACCT += 1; + HHACCT = realloc(HHACCT,sizeof(*HHACCT) * maxHHACCT); + }*/ + hhacct = calloc(1,sizeof(*hhacct)); // &HHACCT[numHHACCT++], memset(hhacct,0,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.fromheight = fromheight; + hhutxo->u.prevunspentind = hhacct->a.lastunspentind; + hhacct->a.lastunspentind = spent_unspentind; + hhacct->a.total += spent_value; + /*if ( iguana_hhutxofind(coin,uval) == 0 || iguana_hhaccountfind(coin,pval) == 0 ) + { + printf("null hh find.(%ld %ld) %p %p\n",(long)uval,(long)pval,iguana_hhutxofind(coin,uval),iguana_hhaccountfind(coin,pval)); + }*/ + return(0); +} + +int32_t iguana_spentflag(struct iguana_info *coin,int64_t *RTspendp,int32_t *spentheightp,struct iguana_ramchain *ramchain,int16_t spent_hdrsi,uint32_t spent_unspentind,int32_t height,int32_t minconf,int32_t maxconf,uint64_t amount) +{ + uint32_t numunspents; struct iguana_hhutxo *hhutxo; struct iguana_utxo utxo; uint64_t confs,val,RTspend = 0; + *spentheightp = 0; + numunspents = ramchain->H.data->numunspents; + memset(&utxo,0,sizeof(utxo)); + val = ((uint64_t)spent_hdrsi << 32) | spent_unspentind; + if ( spent_unspentind != 0 && spent_unspentind < numunspents ) + { + if ( ramchain->Uextras != 0 ) + utxo = ramchain->Uextras[spent_unspentind]; + if ( ramchain->Uextras == 0 || utxo.spentflag == 0 ) + { + //printf("check hhutxo [%d] u%u %p\n",spent_hdrsi,spent_unspentind,iguana_hhutxofind(coin,((uint64_t)202<<32)|3909240)); + if ( (hhutxo= iguana_hhutxofind(coin,val)) != 0 ) + { + utxo = hhutxo->u; + if ( utxo.spentflag != 0 ) + RTspend = amount; + } + } + } + else + { + printf("illegal unspentind.%u vs %u hdrs.%d\n",spent_unspentind,numunspents,spent_hdrsi); + return(-1); + } + if ( utxo.spentflag != 0 && utxo.fromheight == 0 ) + { + printf("illegal unspentind.%u vs %u hdrs.%d zero fromheight?\n",spent_unspentind,numunspents,spent_hdrsi); + return(-1); + } + //printf("[%d] u%u %.8f, spentheight.%d vs height.%d spentflag.%d\n",spent_hdrsi,spent_unspentind,dstr(amount),utxo.fromheight,height,utxo.spentflag); + *spentheightp = utxo.fromheight; + if ( (confs= coin->blocks.hwmchain.height - utxo.fromheight) >= minconf && confs < maxconf && (height == 0 || utxo.fromheight < height) ) + { + (*RTspendp) += RTspend; + return(utxo.spentflag); + } + 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_account *A2; struct iguana_ramchaindata *rdata; struct iguana_utxo *utxo; + if ( (rdata= spentchain->H.data) != 0 ) + { + if ( incremental == 0 ) + { + if ( spentchain->Uextras == 0 || spentchain->A2 == 0 ) + iguana_volatilesmap(coin,spentchain); + 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->spentflag = 1; + utxo->fromheight = fromheight; + A2[spent_pkind].total += spent_value; + A2[spent_pkind].lastunspentind = spent_unspentind; + return(0); + } + else + { + 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 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; + if ( iguana_utxoupdate(coin,spent_hdrsi,spent_unspentind,spent_pkind,spent_value,spendind,fromheight) == 0 ) + { + /*totalmillis += (OS_milliseconds() - startmillis); + if ( (++utxon % 100000) == 0 ) + printf("ave utxo[%d] %.2f micros total %.2f seconds\n",utxon,(1000. * totalmillis)/utxon,totalmillis/1000.);*/ + return(0); + } + } + printf("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); + if ( coin->current != 0 && fromheight >= coin->current->bundleheight ) + coin->RTdatabad = 1; + else + { + printf("from.%d vs current.%d\n",fromheight,coin->current->bundleheight); + iguana_bundleremove(coin,spent_hdrsi,0); + iguana_bundleremove(coin,fromheight/coin->chain->bundlesize,0); + } + exit(-1); + } else printf("volatileupdate error 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 != %ld\n",ramchain->debitsfilesize,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 != %ld\n",ramchain->lastspendsfilesize,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 && ramchain->A2 != ramchain->debitsfileptr+sizeof(bits256)*2+sizeof(int32_t) ) + free(ramchain->A2); + if ( ramchain->allocatedU2 != 0 && ramchain->Uextras != 0 && ramchain->Uextras != 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 ) + 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) * ramchain->H.data->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 && 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) * ramchain->H.data->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 && 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); + //printf("volatilesmap.[%d] %p %p\n",ramchain->height/coin->chain->bundlesize,ramchain->debitsfileptr,ramchain->lastspendsfileptr); + err = 0; + } 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 + { + printf("ramchain.[%d] map error balanceswritten %d vs %d hashes %x %x\n",ramchain->H.data->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); +} diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index 89cf6cb2d..1799337c7 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -29,60 +29,6 @@ void scrubfree(char *sensitivestr) } } -void iguana_walletdelete(struct supernet_info *myinfo,int32_t deleteflag) -{ - struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; int32_t i; - HASH_ITER(hh,myinfo->wallet,wacct,tmp) - { - HASH_ITER(hh,wacct->waddr,waddr,tmp2) - { - memset(&waddr->privkey,0,sizeof(waddr->privkey)); - memset(waddr->wifstr,0,sizeof(waddr->wifstr)); - for (i=0; iprivkey); i++) - waddr->privkey.bytes[i] = rand(); - for (i=0; iwifstr); i++) - waddr->wifstr[i] = rand(); - if ( deleteflag != 0 ) - { - HASH_DELETE(hh,wacct->waddr,waddr); - free(waddr); - } - } - if ( deleteflag != 0 ) - { - HASH_DELETE(hh,myinfo->wallet,wacct); - free(wacct); - } - } -} - -cJSON *iguana_walletjson(struct supernet_info *myinfo) -{ - struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; cJSON *wallet,*account; char scriptstr[4096]; - wallet = cJSON_CreateObject(); - HASH_ITER(hh,myinfo->wallet,wacct,tmp) - { - account = cJSON_CreateObject(); - HASH_ITER(hh,wacct->waddr,waddr,tmp2) - { - if ( bits256_nonz(waddr->privkey) == 0 && waddr->scriptlen == 0 ) - { - free_json(account); - free_json(wallet); - printf("found a null privkey in wallet, abort saving\n"); - return(0); - } - if ( waddr->scriptlen != 0 ) - { - init_hexbytes_noT(scriptstr,waddr->redeemScript,waddr->scriptlen); - jaddstr(account,waddr->coinaddr,scriptstr); - } else jaddbits256(account,waddr->coinaddr,waddr->privkey); - } - jadd(wallet,wacct->account,account); - } - return(wallet); -} - struct iguana_waddress *iguana_waddressfind(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,char *coinaddr) { struct iguana_waddress *waddr; int32_t len = (int32_t)strlen(coinaddr)+1; @@ -91,11 +37,12 @@ struct iguana_waddress *iguana_waddressfind(struct supernet_info *myinfo,struct return(waddr); } -struct iguana_waddress *iguana_waddressalloc(char *symbol,char *coinaddr,char *redeemScript) +struct iguana_waddress *iguana_waddressalloc(uint8_t addrtype,char *symbol,char *coinaddr,char *redeemScript) { struct iguana_waddress *waddr; int32_t scriptlen; scriptlen = (redeemScript != 0) ? ((int32_t)strlen(redeemScript) >> 1) : 0; waddr = mycalloc('w',1,sizeof(*waddr) + scriptlen); + waddr->addrtype = addrtype; strcpy(waddr->coinaddr,coinaddr); strcpy(waddr->symbol,symbol); if ( (waddr->scriptlen= scriptlen) != 0 ) @@ -109,7 +56,7 @@ struct iguana_waddress *iguana_waddresscreate(struct supernet_info *myinfo,struc HASH_FIND(hh,wacct->waddr,coinaddr,len,waddr); if ( waddr == 0 ) { - if ( (waddr= iguana_waddressalloc(coin->symbol,coinaddr,redeemScript)) != 0 ) + if ( (waddr= iguana_waddressalloc(redeemScript==0?coin->chain->pubtype : coin->chain->p2shtype,coin->symbol,coinaddr,redeemScript)) != 0 ) { HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); myinfo->dirty = (uint32_t)time(NULL); @@ -127,7 +74,7 @@ struct iguana_waddress *iguana_waddressadd(struct supernet_info *myinfo,struct i HASH_FIND(hh,wacct->waddr,addwaddr->coinaddr,len,waddr); if ( waddr == 0 ) { - if ( (waddr= iguana_waddressalloc(coin->symbol,addwaddr->coinaddr,redeemScript)) != 0 ) + if ( (waddr= iguana_waddressalloc(redeemScript==0?coin->chain->pubtype : coin->chain->p2shtype,coin->symbol,addwaddr->coinaddr,redeemScript)) != 0 ) { HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); myinfo->dirty = (uint32_t)time(NULL); @@ -157,8 +104,8 @@ struct iguana_waddress *iguana_waddressadd(struct supernet_info *myinfo,struct i strcpy(waddr->coinaddr,addwaddr->coinaddr); if ( waddr->wifstr[0] == 0 ) strcpy(waddr->wifstr,addwaddr->wifstr); + waddr->addrtype = addwaddr->addrtype; waddr->wiftype = addwaddr->wiftype; - waddr->type = addwaddr->type; myinfo->dirty = (uint32_t)time(NULL); } if ( waddr != 0 && waddr->symbol[0] == 0 ) @@ -226,7 +173,7 @@ struct iguana_waddress *iguana_waddresscalc(uint8_t pubtype,uint8_t wiftype,stru if ( bitcoin_priv2wif(addr->wifstr,addr->privkey,wiftype) > 0 ) { addr->wiftype = wiftype; - addr->type = pubtype; + addr->addrtype = pubtype; return(addr); } return(0); @@ -263,7 +210,7 @@ uint8_t *iguana_walletrmds(struct supernet_info *myinfo,struct iguana_info *coin n++; else if ( m < n ) { - addrtypes[m] = waddr->type; + addrtypes[m] = waddr->addrtype; memcpy(&rmdarray[m * 20],waddr->rmd160,20); memcpy(&pubkeys[m * 33],waddr->pubkey,33); m++; @@ -295,52 +242,6 @@ cJSON *getaddressesbyaccount(struct supernet_info *myinfo,struct iguana_info *co return(array); } -/*struct iguana_waddress *iguana_waccountadd(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount **wacctp,char *walletaccount,char *coinaddr,char *redeemScript) -{ - struct iguana_waccount *wacct; struct iguana_waddress *waddr = 0; - if ( (wacct= iguana_waccountfind(myinfo,coin,walletaccount)) == 0 ) - wacct = iguana_waccountcreate(myinfo,coin,walletaccount); - if ( wacct != 0 ) - waddr = iguana_waddresscreate(myinfo,coin,wacct,coinaddr,redeemScript); - return(waddr); -}*/ - -void iguana_walletlock(struct supernet_info *myinfo) -{ - memset(&myinfo->persistent_priv,0,sizeof(myinfo->persistent_priv)); - memset(myinfo->secret,0,sizeof(myinfo->secret)); - memset(myinfo->permanentfile,0,sizeof(myinfo->permanentfile)); - if ( myinfo->decryptstr != 0 ) - scrubfree(myinfo->decryptstr), myinfo->decryptstr = 0; - myinfo->expiration = 0; - iguana_walletdelete(myinfo,0); - //printf("wallet locked\n"); -} - -uint8_t *iguana_rmdarray(struct iguana_info *coin,int32_t *numrmdsp,cJSON *array,int32_t firsti) -{ - int32_t i,n,j=0; char *coinaddr,rmdstr[41]; uint8_t *addrtypes,*rmdarray = 0; - *numrmdsp = 0; - if ( array != 0 && (n= cJSON_GetArraySize(array)) > 0 ) - { - *numrmdsp = n - firsti; - rmdarray = calloc(1,(n-firsti) * (21 + 33)); - addrtypes = &rmdarray[(n-firsti) * 20]; - for (i=firsti; iredeemScript,waddr->scriptlen); - jaddstr(retjson,"redeemScript",str); - memset(debugtxid.bytes,0,sizeof(debugtxid)); - if ( (type= iguana_calcrmd160(coin,0,&V,waddr->redeemScript,waddr->scriptlen, debugtxid,-1,0xffffffff)) >= 0 ) - { - privkeys = cJSON_CreateArray(); - pubkeys = cJSON_CreateArray(); - addresses = cJSON_CreateArray(); - for (i=0; iwifstr[0] != 0 ) - jaddistr(privkeys,waddr->wifstr); - else jaddistr(privkeys,""); - if ( (plen= bitcoin_pubkeylen(V.signers[i].pubkey)) > 0 ) - { - init_hexbytes_noT(str,V.signers[i].pubkey,plen); - jaddistr(pubkeys,str); - } else jaddistr(pubkeys,""); - jaddistr(addresses,V.signers[i].coinaddr); - } - jaddstr(retjson,"result",V.coinaddr); - jaddnum(retjson,"M",V.M); - jaddnum(retjson,"N",V.N); - jadd(retjson,"pubkeys",pubkeys); - jadd(retjson,"privkeys",privkeys); - jadd(retjson,"addresses",addresses); - } - return(retjson); -} - cJSON *iguana_waddressjson(cJSON *item,struct iguana_waddress *waddr) { char str[256],redeemScript[4096]; @@ -450,81 +316,12 @@ char *getaccount(struct supernet_info *myinfo,struct iguana_info *coin,char *coi } else return(clonestr("{\"result\":\"\"}")); } -char *sendtoaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,double amount,char *comment,char *comment2) -{ - uint8_t addrtype,rmd160[20]; - //sendtoaddress [comment] [comment-to] is a real and is rounded to 8 decimal places. Returns the transaction ID if successful. Y - if ( coinaddr != 0 && coinaddr[0] != 0 && amount > 0. ) - { - if ( iguana_addressvalidate(coin,&addrtype,rmd160,coinaddr) < 0 ) - return(clonestr("{\"error\":\"invalid coin address\"}")); - //amount = jdouble(params[1],0); - //comment = jstr(params[2],0); - //comment2 = jstr(params[3],0); - printf("need to generate send %.8f to %s [%s] [%s]\n",dstr(amount),coinaddr,comment!=0?comment:"",comment2!=0?comment2:""); - } - return(clonestr("{\"error\":\"need address and amount\"}")); -} - char *jsuccess() { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -bits256 iguana_str2priv(struct supernet_info *myinfo,struct iguana_info *coin,char *str) -{ - bits256 privkey; int32_t n; uint8_t addrtype; struct iguana_waccount *wacct=0; struct iguana_waddress *waddr; - memset(&privkey,0,sizeof(privkey)); - if ( str != 0 ) - { - n = (int32_t)strlen(str) >> 1; - if ( n == sizeof(bits256) && is_hexstr(str,sizeof(bits256)) > 0 ) - decode_hex(privkey.bytes,sizeof(privkey),str); - else if ( bitcoin_wif2priv(&addrtype,&privkey,str) != sizeof(bits256) ) - { - if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,str)) != 0 ) - privkey = waddr->privkey; - else memset(privkey.bytes,0,sizeof(privkey)); - } - } - return(privkey); -} - -int32_t iguana_pubkeyget(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *pubkey33,char *str) -{ - bits256 privkey,pubkey; uint8_t pubkeydata[128]; int32_t len,plen= -1; struct iguana_waccount *wacct; struct iguana_waddress *waddr; - len = (int32_t)strlen(str); - if ( is_hexstr(str,len) == 0 ) - { - if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,str)) != 0 ) - { - if ( (plen= bitcoin_pubkeylen(waddr->pubkey)) > 0 ) - memcpy(pubkeydata,waddr->pubkey,plen); - } - } - else - { - decode_hex(pubkeydata,len,str); - plen = bitcoin_pubkeylen(pubkeydata); - } - if ( plen <= 0 ) - { - privkey = iguana_str2priv(myinfo,coin,str); - if ( bits256_nonz(privkey) == 0 ) - return(-1); - else - { - pubkey = bitcoin_pubkey33(pubkeydata,privkey); - if ( bits256_nonz(pubkey) == 0 ) - return(-1); - } - } - if ( (plen= bitcoin_pubkeylen(pubkeydata)) > 0 ) - memcpy(pubkey33,pubkeydata,plen); - return(0); -} - char *iguana_addressconv(struct iguana_info *coin,char *destaddr,struct iguana_info *other,int32_t isp2sh,uint8_t rmd160[20]) { if ( bitcoin_address(destaddr,isp2sh != 0 ? other->chain->pubtype : other->chain->p2shtype,rmd160,20) == destaddr ) @@ -582,6 +379,31 @@ int32_t iguana_payloadupdate(struct supernet_info *myinfo,struct iguana_info *co return(retval); } +cJSON *iguana_payloadmerge(cJSON *loginjson,cJSON *importjson) +{ + cJSON *retjson,*item,*obj; char *field; + if ( loginjson == 0 ) + return(importjson); + else if ( importjson == 0 ) + return(loginjson); + retjson = jduplicate(loginjson); + item = importjson->child; + while ( item != 0 ) + { + if ( (field= jfieldname(item)) != 0 ) + { + if ( (obj= jobj(retjson,field)) == 0 ) + { + if ( strlen(field) == 20*2 ) + jaddstr(retjson,field,jstr(item,0)); + else jaddbits256(retjson,field,jbits256(item,0)); + } + } + item = item->next; + } + return(retjson); +} + cJSON *iguana_walletadd(struct supernet_info *myinfo,struct iguana_waddress **waddrp,struct iguana_info *coin,char *retstr,char *account,struct iguana_waddress *refwaddr,int32_t setcurrent,char *redeemScript) { cJSON *retjson=0; struct iguana_waccount *wacct; struct iguana_waddress *waddr; @@ -610,9 +432,225 @@ cJSON *iguana_walletadd(struct supernet_info *myinfo,struct iguana_waddress **wa return(retjson); } +cJSON *iguana_walletjson(struct supernet_info *myinfo) +{ + struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; cJSON *wallet,*account; char scriptstr[4096]; + wallet = cJSON_CreateObject(); + HASH_ITER(hh,myinfo->wallet,wacct,tmp) + { + account = cJSON_CreateObject(); + HASH_ITER(hh,wacct->waddr,waddr,tmp2) + { + if ( bits256_nonz(waddr->privkey) == 0 && waddr->scriptlen == 0 ) + { + free_json(account); + free_json(wallet); + printf("found a null privkey in wallet, abort saving\n"); + return(0); + } + if ( waddr->scriptlen != 0 ) + { + init_hexbytes_noT(scriptstr,waddr->redeemScript,waddr->scriptlen); + jaddstr(account,waddr->coinaddr,scriptstr); + } else jaddbits256(account,waddr->coinaddr,waddr->privkey); + } + jadd(wallet,wacct->account,account); + } + return(wallet); +} + +void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coin) +{ + // "wallet":{"test":{"R9S7zZzzvgb4CkiBH1i7gnFcwJuL1MYbxN":"18ab9c89ce83929db720cf26b663bf762532276146cd9d3e1f89086fcdf00053"}} + cJSON *payload,*item,*array,*child; char *account,*coinaddr,*privkeystr; int32_t i,j,n,len; struct iguana_waccount *wacct,*tmp; struct iguana_waddress waddr; bits256 privkey; uint8_t addrtype,rmd160[20]; + if ( myinfo->wallet == 0 && myinfo->decryptstr != 0 && (payload= cJSON_Parse(myinfo->decryptstr)) != 0 ) + { + if ( (array= jobj(payload,"wallet")) != 0 ) + { + n = cJSON_GetArraySize(array); + //printf("item.(%s) size.%d\n",jprint(array,0),n); + item = array->child; + for (i=0; istring) != 0 ) + { + child = item->child; + while ( child != 0 ) + { + coinaddr = child->string; + privkeystr = child->valuestring; + if ( coinaddr != 0 && privkeystr != 0 ) + { + if ( (wacct= iguana_waccountcreate(myinfo,coin,account)) != 0 ) + { + if ( iguana_waddresssearch(myinfo,coin,&tmp,coinaddr) == 0 ) + { + memset(&waddr,0,sizeof(waddr)); + strcpy(waddr.coinaddr,coinaddr); + waddr.addrtype = coin->chain->p2shtype; + if ( bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr) == sizeof(rmd160) && addrtype == coin->chain->p2shtype ) + iguana_waddressadd(myinfo,coin,wacct,&waddr,privkeystr); + else + { + waddr.addrtype = coin->chain->pubtype; + privkey = bits256_conv(privkeystr); + if ( iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&waddr,privkey) != 0 ) + iguana_waddressadd(myinfo,coin,wacct,&waddr,0); + } + } else printf("dup.(%s) ",coinaddr); + len = (int32_t)strlen(privkeystr); + for (j=0; jnext; + } + printf("account.(%s)\n",account); + } + item = item->next; + } + } + free_json(payload); + myinfo->decryptstr = 0; + scrubfree(myinfo->decryptstr); + myinfo->dirty = 0; + } +} + +int32_t iguana_walletemit(struct supernet_info *myinfo,char *fname,struct iguana_info *coin,cJSON *array) +{ + cJSON *item,*child; uint8_t addrtype,wiftype,rmd160[20]; char p2shaddr[128],str[64],wifstr[128],*account,*coinaddr,*privkeystr; int32_t i,j,n; FILE *fp; bits256 privkey; + if ( (fp= fopen(fname,"wb")) == 0 ) + return(-1); + n = cJSON_GetArraySize(array); + item = array->child; + for (i=0; istring) != 0 ) + { + child = item->child; + while ( child != 0 ) + { + coinaddr = child->string; + privkeystr = child->valuestring; + if ( coinaddr != 0 && privkeystr != 0 ) + { + bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); + wiftype = 188; + for (j=0; jchain != 0 ) + { + if ( addrtype == coin->chain->pubtype ) + { + wiftype = coin->chain->wiftype; + privkey = bits256_conv(privkeystr); + if ( bitcoin_priv2wif(wifstr,privkey,wiftype) > 0 ) + { + fprintf(fp,"%s %s %32s=%d # addr=%s\n",wifstr,utc_str(str,(uint32_t)time(NULL)),account,i+1,coinaddr); + } + break; + } + else if ( addrtype == coin->chain->p2shtype ) + { + fprintf(fp,"%s %s %32s=%d # addr=%s # p2sh\n",privkeystr,utc_str(str,(uint32_t)time(NULL)),account,i+1,p2shaddr); + break; + } + } + } + } + child = child->next; + } + //printf("account.(%s)\n",account); + } + item = item->next; + } + fclose(fp); + return(0); +} + +void iguana_walletdelete(struct supernet_info *myinfo,int32_t deleteflag) +{ + struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; int32_t i; + HASH_ITER(hh,myinfo->wallet,wacct,tmp) + { + HASH_ITER(hh,wacct->waddr,waddr,tmp2) + { + memset(&waddr->privkey,0,sizeof(waddr->privkey)); + memset(waddr->wifstr,0,sizeof(waddr->wifstr)); + for (i=0; iprivkey); i++) + waddr->privkey.bytes[i] = rand(); + for (i=0; iwifstr); i++) + waddr->wifstr[i] = rand(); + if ( deleteflag != 0 ) + { + HASH_DELETE(hh,wacct->waddr,waddr); + free(waddr); + } + } + if ( deleteflag != 0 ) + { + HASH_DELETE(hh,myinfo->wallet,wacct); + free(wacct); + } + } +} + +void iguana_walletlock(struct supernet_info *myinfo) +{ + memset(&myinfo->persistent_priv,0,sizeof(myinfo->persistent_priv)); + memset(myinfo->secret,0,sizeof(myinfo->secret)); + memset(myinfo->permanentfile,0,sizeof(myinfo->permanentfile)); + if ( myinfo->decryptstr != 0 ) + scrubfree(myinfo->decryptstr), myinfo->decryptstr = 0; + myinfo->expiration = 0; + iguana_walletdelete(myinfo,0); +} + +int64_t iguana_waccountbalance(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,int32_t minconf,int32_t lastheight) +{ + int64_t balance; int32_t numrmds=0; uint8_t *rmdarray=0; + if ( minconf == 0 ) + minconf = 1; + rmdarray = iguana_rmdarray(coin,&numrmds,getaddressesbyaccount(myinfo,coin,wacct->account),0); + balance = iguana_unspents(myinfo,coin,0,minconf,(1 << 30),rmdarray,numrmds,lastheight,0,0); + if ( rmdarray != 0 ) + free(rmdarray); + return(balance); +} + #include "../includes/iguana_apidefs.h" #include "../includes/iguana_apideclares.h" +int64_t iguana_addressreceived(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *json,char *remoteaddr,cJSON *txids,cJSON *vouts,char *coinaddr,int32_t minconf) +{ + int64_t balance = 0; cJSON *unspentsjson,*balancejson,*item; int32_t i,n; char *balancestr; + if ( (balancestr= iguana_balance(IGUANA_CALLARGS,coin->symbol,coinaddr,-1,minconf)) != 0 ) + { + if ( (balancejson= cJSON_Parse(balancestr)) != 0 ) + { + balance = jdouble(balancejson,"balance") * SATOSHIDEN; + if ( (txids != 0 || vouts != 0) && (unspentsjson= jarray(&n,balancejson,"unspents")) != 0 ) + { + for (i=0; iexpiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) - { - free(retstr); - retstr = myinfo->decryptstr, myinfo->decryptstr = 0; - newretstr = getnewaddress(myinfo,&waddr,coin,account,retstr); - if ( retstr != 0 ) - scrubfree(retstr); - return(newretstr); - } - else return(clonestr("{\"error\":\"no wallet payload\"}")); -} - -STRING_ARG(bitcoinrpc,getaccountaddress,account) -{ - char *retstr,*newstr; struct iguana_waccount *wacct; struct iguana_waddress *waddr=0; cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - if ( account != 0 && account[0] != 0 ) - { - if ( (wacct= iguana_waccountfind(myinfo,coin,account)) == 0 ) - wacct = iguana_waccountcreate(myinfo,coin,account); - if ( wacct != 0 ) - { - if ( (waddr= wacct->current) == 0 ) - { - if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) - { - free(retstr); - retstr = myinfo->decryptstr, myinfo->decryptstr = 0; - printf("loginstr.(%s)\n",retstr); - newstr = getnewaddress(myinfo,&waddr,coin,account,retstr); - if ( retstr != 0 ) - scrubfree(retstr); - retstr = newstr; - } else return(clonestr("{\"error\":\"no wallet payload\"}")); - } - if ( waddr != 0 ) - retjson = iguana_waddressjson(0,waddr); - else return(clonestr("{\"error\":\"couldnt create address\"}")); - jaddstr(retjson,"account",account); - jaddstr(retjson,"result","success"); - return(jprint(retjson,1)); - } else return(clonestr("{\"error\":\"cant find account\"}")); - } - return(clonestr("{\"error\":\"no account specified\"}")); -} - -ZERO_ARGS(bitcoinrpc,walletlock) -{ - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - iguana_walletlock(myinfo); - return(jsuccess()); -} - -void iguana_walletinitcheck(struct supernet_info *myinfo,struct iguana_info *coin) -{ - // "wallet":{"test":{"R9S7zZzzvgb4CkiBH1i7gnFcwJuL1MYbxN":"18ab9c89ce83929db720cf26b663bf762532276146cd9d3e1f89086fcdf00053"}} - cJSON *payload,*item,*array,*child; char *account,*coinaddr,*privkeystr; int32_t i,j,n,len; struct iguana_waccount *wacct,*tmp; struct iguana_waddress waddr; bits256 privkey; uint8_t addrtype,rmd160[20]; - if ( myinfo->wallet == 0 && myinfo->decryptstr != 0 && (payload= cJSON_Parse(myinfo->decryptstr)) != 0 ) - { - if ( (array= jobj(payload,"wallet")) != 0 ) - { - n = cJSON_GetArraySize(array); - //printf("item.(%s) size.%d\n",jprint(array,0),n); - item = array->child; - for (i=0; istring) != 0 ) - { - child = item->child; - while ( child != 0 ) - { - coinaddr = child->string; - privkeystr = child->valuestring; - if ( coinaddr != 0 && privkeystr != 0 ) - { - if ( (wacct= iguana_waccountcreate(myinfo,coin,account)) != 0 ) - { - if ( iguana_waddresssearch(myinfo,coin,&tmp,coinaddr) == 0 ) - { - memset(&waddr,0,sizeof(waddr)); - strcpy(waddr.coinaddr,coinaddr); - if ( bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr) == sizeof(rmd160) && addrtype == coin->chain->p2shtype ) - iguana_waddressadd(myinfo,coin,wacct,&waddr,privkeystr); - else - { - privkey = bits256_conv(privkeystr); - if ( iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&waddr,privkey) != 0 ) - iguana_waddressadd(myinfo,coin,wacct,&waddr,0); - } - } else printf("dup.(%s) ",coinaddr); - len = (int32_t)strlen(privkeystr); - for (j=0; jnext; - } - printf("account.(%s)\n",account); - } - item = item->next; - } - } - free_json(payload); - myinfo->decryptstr = 0; - scrubfree(myinfo->decryptstr); - myinfo->dirty = 0; + char *retstr,*newretstr; struct iguana_waddress *waddr; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) + { + free(retstr); + retstr = myinfo->decryptstr, myinfo->decryptstr = 0; + newretstr = getnewaddress(myinfo,&waddr,coin,account,retstr); + if ( retstr != 0 ) + scrubfree(retstr); + return(newretstr); } + else return(clonestr("{\"error\":\"no wallet payload\"}")); } -int32_t iguana_walletemit(struct supernet_info *myinfo,char *fname,struct iguana_info *coin,cJSON *array) +STRING_ARG(bitcoinrpc,getaccountaddress,account) { - cJSON *item,*child; uint8_t addrtype,wiftype,rmd160[20]; char p2shaddr[128],str[64],wifstr[128],*account,*coinaddr,*privkeystr; int32_t i,j,n; FILE *fp; bits256 privkey; - if ( (fp= fopen(fname,"wb")) == 0 ) - return(-1); - n = cJSON_GetArraySize(array); - item = array->child; - for (i=0; iexpiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + if ( account != 0 && account[0] != 0 ) { - if ( item != 0 && (account= item->string) != 0 ) + if ( (wacct= iguana_waccountfind(myinfo,coin,account)) == 0 ) + wacct = iguana_waccountcreate(myinfo,coin,account); + if ( wacct != 0 ) { - child = item->child; - while ( child != 0 ) + if ( (waddr= wacct->current) == 0 ) { - coinaddr = child->string; - privkeystr = child->valuestring; - if ( coinaddr != 0 && privkeystr != 0 ) + if ( (retstr= SuperNET_login(IGUANA_CALLARGS,myinfo->handle,myinfo->secret,myinfo->permanentfile,0)) != 0 ) { - bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); - wiftype = 188; - for (j=0; jchain != 0 ) - { - if ( addrtype == coin->chain->pubtype ) - { - wiftype = coin->chain->wiftype; - privkey = bits256_conv(privkeystr); - if ( bitcoin_priv2wif(wifstr,privkey,wiftype) > 0 ) - { - fprintf(fp,"%s %s %32s=%d # addr=%s\n",wifstr,utc_str(str,(uint32_t)time(NULL)),account,i+1,coinaddr); - } - break; - } - else if ( addrtype == coin->chain->p2shtype ) - { - fprintf(fp,"%s %s %32s=%d # addr=%s # p2sh\n",privkeystr,utc_str(str,(uint32_t)time(NULL)),account,i+1,p2shaddr); - break; - } - } - } - } - child = child->next; + free(retstr); + retstr = myinfo->decryptstr, myinfo->decryptstr = 0; + printf("loginstr.(%s)\n",retstr); + newstr = getnewaddress(myinfo,&waddr,coin,account,retstr); + if ( retstr != 0 ) + scrubfree(retstr); + retstr = newstr; + } else return(clonestr("{\"error\":\"no wallet payload\"}")); } - //printf("account.(%s)\n",account); - } - item = item->next; + if ( waddr != 0 ) + retjson = iguana_waddressjson(0,waddr); + else return(clonestr("{\"error\":\"couldnt create address\"}")); + jaddstr(retjson,"account",account); + jaddstr(retjson,"result","success"); + return(jprint(retjson,1)); + } else return(clonestr("{\"error\":\"cant find account\"}")); } - fclose(fp); - return(0); + return(clonestr("{\"error\":\"no account specified\"}")); +} + +ZERO_ARGS(bitcoinrpc,walletlock) +{ + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + iguana_walletlock(myinfo); + return(jsuccess()); } TWOSTRINGS_AND_INT(bitcoinrpc,walletpassphrase,password,permanentfile,timeout) @@ -1006,32 +933,6 @@ STRING_ARG(bitcoinrpc,dumpprivkey,address) } else return(clonestr("{\"error\":\"no privkey for address\"}")); } -ZERO_ARGS(bitcoinrpc,checkwallet) -{ - cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - retjson = cJSON_CreateObject(); - jaddstr(retjson,"result","success"); - return(jprint(retjson,1)); -} - -ZERO_ARGS(bitcoinrpc,repairwallet) -{ - cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - retjson = cJSON_CreateObject(); - jaddstr(retjson,"result","success"); - return(jprint(retjson,1)); -} - STRING_ARG(bitcoinrpc,dumpwallet,filename) { char *retstr,*walletstr; cJSON *retjson,*walletobj,*strobj; @@ -1090,31 +991,6 @@ STRING_ARG(bitcoinrpc,backupwallet,filename) } else return(clonestr("{\"error\":\"need to unlock wallet\"}")); } -cJSON *iguana_payloadmerge(cJSON *loginjson,cJSON *importjson) -{ - cJSON *retjson,*item,*obj; char *field; - if ( loginjson == 0 ) - return(importjson); - else if ( importjson == 0 ) - return(loginjson); - retjson = jduplicate(loginjson); - item = importjson->child; - while ( item != 0 ) - { - if ( (field= jfieldname(item)) != 0 ) - { - if ( (obj= jobj(retjson,field)) == 0 ) - { - if ( strlen(field) == 20*2 ) - jaddstr(retjson,field,jstr(item,0)); - else jaddbits256(retjson,field,jbits256(item,0)); - } - } - item = item->next; - } - return(retjson); -} - STRING_ARG(bitcoinrpc,importwallet,filename) { cJSON *retjson = 0,*importjson,*loginjson = 0; long filesize; char *importstr,*loginstr; @@ -1162,7 +1038,7 @@ STRING_AND_THREEINTS(bitcoinrpc,getbalance,account,minconf,includeempty,lastheig minconf = 1; if ( strcmp(account,"*") != 0 ) rmdarray = iguana_rmdarray(coin,&numrmds,getaddressesbyaccount(myinfo,coin,account),0); - balance = iguana_unspents(myinfo,coin,0,minconf,(1 << 30),rmdarray,numrmds,lastheight); + balance = iguana_unspents(myinfo,coin,0,minconf,(1 << 30),rmdarray,numrmds,lastheight,0,0); if ( rmdarray != 0 ) free(rmdarray); retjson = cJSON_CreateObject(); @@ -1180,18 +1056,6 @@ STRING_ARG(bitcoinrpc,getaddressesbyaccount,account) return(jprint(retjson,1)); } -int64_t iguana_waccountbalance(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,int32_t minconf,int32_t lastheight) -{ - int64_t balance; int32_t numrmds=0; uint8_t *rmdarray=0; - if ( minconf == 0 ) - minconf = 1; - rmdarray = iguana_rmdarray(coin,&numrmds,getaddressesbyaccount(myinfo,coin,wacct->account),0); - balance = iguana_unspents(myinfo,coin,0,minconf,(1 << 30),rmdarray,numrmds,lastheight); - if ( rmdarray != 0 ) - free(rmdarray); - return(balance); -} - STRING_AND_INT(bitcoinrpc,getreceivedbyaccount,account,minconf) { cJSON *retjson; struct iguana_waccount *wacct; int64_t balance; @@ -1348,167 +1212,5 @@ TWO_INTS(bitcoinrpc,listaccounts,minconf,includewatchonly) return(jprint(retjson,1)); } -HASH_AND_TWOINTS(bitcoinrpc,listsinceblock,blockhash,target,flag) -{ - cJSON *retjson = cJSON_CreateObject(); - return(jprint(retjson,1)); -} - -INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,pubkeys,ignore) -{ - cJSON *retjson,*pkjson,*addresses; uint8_t script[2048],p2sh_rmd160[20]; char pubkeystr[256],msigaddr[64],*pkstr,scriptstr[sizeof(script)*2+1]; struct vin_info V; int32_t i,plen,len,n = cJSON_GetArraySize(pubkeys); - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( n < 0 || n > 16 || M < 0 || M > n ) - return(clonestr("{\"error\":\"illegal number of pubkeys\"}")); - memset(&V,0,sizeof(V)); - V.M = M, V.N = n; - pkjson = cJSON_CreateArray(); - addresses = cJSON_CreateArray(); - for (i=0; ichain->pubtype,V.signers[i].pubkey,plen); - jaddistr(addresses,V.signers[i].coinaddr); - init_hexbytes_noT(pubkeystr,V.signers[i].pubkey,plen); - jaddistr(pkjson,pubkeystr); - } else break; - } - retjson = cJSON_CreateObject(); - if ( i == n ) - { - len = bitcoin_MofNspendscript(p2sh_rmd160,script,0,&V); - bitcoin_address(msigaddr,coin->chain->p2shtype,p2sh_rmd160,sizeof(p2sh_rmd160)); - jaddstr(retjson,"result","success"); - jaddstr(retjson,"address",msigaddr); - init_hexbytes_noT(scriptstr,script,len); - jaddstr(retjson,"redeemScript",scriptstr); - jaddnum(retjson,"M",M); - jaddnum(retjson,"N",n); - jadd(retjson,"pubkeys",pkjson); - jadd(retjson,"addresses",addresses); - } - else - { - jaddstr(retjson,"error","couldnt get all pubkeys"); - free_json(pkjson); - } - return(jprint(retjson,1)); -} - -INT_ARRAY_STRING(bitcoinrpc,addmultisigaddress,M,pubkeys,account) // -{ - cJSON *retjson,*tmpjson,*setjson=0; char *retstr,*str=0,*msigaddr,*redeemScript; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - if ( (retstr= bitcoinrpc_createmultisig(IGUANA_CALLARGS,M,pubkeys,account)) != 0 ) - { - //printf("CREATEMULTISIG.(%s)\n",retstr); - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (msigaddr= jstr(retjson,"address")) != 0 ) - { - if ( (redeemScript= jstr(retjson,"redeemScript")) == 0 || (str= setaccount(myinfo,coin,0,account,msigaddr,redeemScript)) == 0 || (setjson= cJSON_Parse(str)) == 0 || jobj(setjson,"error") != 0 ) - { - if ( jobj(retjson,"result") != 0 ) - jdelete(retjson,"result"); - if ( jobj(retjson,"error") == 0 ) - jaddstr(retjson,"error","couldnt add multisig address to account"); - } - else - { - tmpjson = cJSON_CreateObject(); - jaddstr(tmpjson,"result",msigaddr); - free_json(retjson); - free(retstr); - retjson = tmpjson; - } - } - if ( setjson != 0 ) - free_json(setjson); - if ( str != 0 ) - free(str); - return(jprint(retjson,1)); - } else return(clonestr("{\"error\":\"couldnt parse retstr from createmultisig\"}")); - } else return(clonestr("{\"error\":\"no retstr from createmultisig\"}")); -} - -STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees) -{ - cJSON *retjson = cJSON_CreateObject(); - return(jprint(retjson,1)); -} - -DOUBLE_ARG(bitcoinrpc,settxfee,amount) -{ - cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - coin->txfee_perkb = amount * SATOSHIDEN; - retjson = cJSON_CreateObject(); - jadd(retjson,"result",jtrue()); - return(jprint(retjson,1)); -} - -S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2) -{ - cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - retjson = cJSON_CreateObject(); - return(jsuccess()); -} - -SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2) -{ - cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - retjson = cJSON_CreateObject(); - return(jsuccess()); -} - -SS_D_I_S(bitcoinrpc,move,fromaccount,toaccount,amount,minconf,comment) -{ - cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - retjson = cJSON_CreateObject(); - return(jprint(retjson,1)); -} - -S_A_I_S(bitcoinrpc,sendmany,fromaccount,array,minconf,comment) -{ - cJSON *retjson; - if ( remoteaddr != 0 ) - return(clonestr("{\"error\":\"no remote\"}")); - if ( myinfo->expiration == 0 ) - return(clonestr("{\"error\":\"need to unlock wallet\"}")); - myinfo->expiration++; - retjson = cJSON_CreateObject(); - return(jprint(retjson,1)); -} - - #include "../includes/iguana_apiundefs.h" diff --git a/iguana/main.c b/iguana/main.c index 8d750dd7f..0b5cc8609 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -1146,7 +1146,7 @@ void iguana_appletests(struct supernet_info *myinfo) exit(-1); } sleep(1);*/ - if ( 1 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"RELAY\":0,\"VALIDATE\":0,\"prefetchlag\":-1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":500,\"endpend\":500,\"services\":128,\"maxpeers\":64,\"newcoin\":\"BTC\",\"active\":1,\"numhelpers\":4,\"poll\":100}"),0,myinfo->rpcport)) != 0 ) + if ( 1 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":500,\"endpend\":500,\"services\":128,\"maxpeers\":64,\"newcoin\":\"BTCD\",\"active\":1,\"numhelpers\":4,\"poll\":100}"),0,myinfo->rpcport)) != 0 ) { free(str); if ( 0 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"userhome\":\"/Users/jimbolaptop/Library/Application Support\",\"agent\":\"iguana\",\"method\":\"addcoin\",\"services\":1024,\"maxpeers\":256,\"newcoin\":\"BTCD\",\"active\":1}"),0,myinfo->rpcport)) != 0 ) diff --git a/iguana/ramchain_api.c b/iguana/ramchain_api.c index 8d5146171..306bab065 100755 --- a/iguana/ramchain_api.c +++ b/iguana/ramchain_api.c @@ -16,6 +16,53 @@ #include "iguana777.h" #include "../includes/iguana_apidefs.h" +STRING_ARG(iguana,initfastfind,activecoin) +{ + if ( (coin= iguana_coinfind(activecoin)) != 0 ) + { + iguana_fastfindcreate(coin); + return(clonestr("{\"result\":\"fast find initialized\"}")); + } else return(clonestr("{\"error\":\"no coin to initialize\"}")); +} + +TWO_STRINGS_AND_TWO_DOUBLES(iguana,balance,activecoin,address,lastheightd,minconfd) +{ + int32_t lastheight,minconf,maxconf=SATOSHIDEN; int64_t total=0; uint8_t rmd160[20],pubkey33[33],addrtype; + struct iguana_pkhash *P; cJSON *array,*retjson = cJSON_CreateObject(); + if ( activecoin != 0 && activecoin[0] != 0 ) + coin = iguana_coinfind(activecoin); + if ( coin != 0 ) + { + if ( (minconf= minconfd) <= 0 ) + minconf = 1; + lastheight = lastheightd; + jaddstr(retjson,"address",address); + if ( bitcoin_validaddress(coin,address) < 0 ) + { + jaddstr(retjson,"error","illegal address"); + return(jprint(retjson,1)); + } + if ( bitcoin_addr2rmd160(&addrtype,rmd160,address) < 0 ) + { + jaddstr(retjson,"error","cant convert address"); + return(jprint(retjson,1)); + } + memset(pubkey33,0,sizeof(pubkey33)); + P = calloc(coin->bundlescount,sizeof(*P)); + array = cJSON_CreateArray(); + printf("Start %s balance.(%s) height.%d\n",coin->symbol,address,lastheight); + if ( lastheight == 0 ) + lastheight = IGUANA_MAXHEIGHT; + iguana_pkhasharray(myinfo,coin,array,minconf,maxconf,&total,P,coin->bundlescount,rmd160,address,pubkey33,lastheight,0,0); + free(P); + jadd(retjson,"unspents",array); + jaddnum(retjson,"balance",dstr(total)); + if ( lastheight > 0 ) + jaddnum(retjson,"lastheight",lastheight); + } + return(jprint(retjson,1)); +} + STRING_ARG(iguana,validate,activecoin) { int32_t i,total,validated; struct iguana_bundle *bp; cJSON *retjson; @@ -71,32 +118,6 @@ STRING_ARG(iguana,removecoin,activecoin) return(clonestr("{\"error\":\"no active coin\"}")); } -char *iguana_APIrequest(struct iguana_info *coin,bits256 blockhash,bits256 txid,int32_t seconds) -{ - int32_t i,len; char *retstr = 0; uint8_t serialized[1024]; char str[65]; - coin->APIblockhash = blockhash; - coin->APItxid = txid; - printf("request block.(%s) txid.%llx\n",bits256_str(str,blockhash),(long long)txid.txid); - if ( (len= iguana_getdata(coin,serialized,MSG_BLOCK,&blockhash,1)) > 0 ) - { - for (i=0; iAPIblockstr != 0 ) - { - retstr = coin->APIblockstr; - coin->APIblockstr = 0; - memset(&coin->APIblockhash,0,sizeof(coin->APIblockhash)); - memset(&coin->APItxid,0,sizeof(coin->APItxid)); - return(retstr); - } - sleep(1); - } - } - return(0); -} - INT_ARG(bitcoinrpc,getblockhash,height) { cJSON *retjson = cJSON_CreateObject(); @@ -140,71 +161,6 @@ HASH_AND_TWOINTS(bitcoinrpc,getblock,blockhash,verbose,remoteonly) return(jprint(retjson,1)); } -HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose) -{ - struct iguana_txid *tx,T; char *txbytes; bits256 checktxid; int32_t len,height; cJSON *retjson; - if ( (tx= iguana_txidfind(coin,&height,&T,txid,coin->bundlescount-1)) != 0 ) - { - retjson = cJSON_CreateObject(); - if ( (len= iguana_ramtxbytes(coin,coin->blockspace,sizeof(coin->blockspace),&checktxid,tx,height,0,0,0)) > 0 ) - { - txbytes = calloc(1,len*2+1); - init_hexbytes_noT(txbytes,coin->blockspace,len); - jaddstr(retjson,"result",txbytes); - printf("txbytes.(%s) len.%d (%s)\n",txbytes,len,jprint(retjson,0)); - free(txbytes); - return(jprint(retjson,1)); - } - else if ( height >= 0 ) - { - if ( coin->APIblockstr != 0 ) - jaddstr(retjson,"error","already have pending request"); - else - { - int32_t datalen; uint8_t *data; char *blockstr; bits256 blockhash; - blockhash = iguana_blockhash(coin,height); - if ( (blockstr= iguana_APIrequest(coin,blockhash,txid,2)) != 0 ) - { - datalen = (int32_t)(strlen(blockstr) >> 1); - data = malloc(datalen); - decode_hex(data,datalen,blockstr); - if ( (txbytes= iguana_txscan(coin,verbose != 0 ? retjson : 0,data,datalen,txid)) != 0 ) - { - jaddstr(retjson,"result",txbytes); - jaddbits256(retjson,"blockhash",blockhash); - jaddnum(retjson,"height",height); - free(txbytes); - } else jaddstr(retjson,"error","cant find txid in block"); - free(blockstr); - free(data); - } else jaddstr(retjson,"error","cant find blockhash"); - return(jprint(retjson,1)); - } - } else printf("height.%d\n",height); - } - return(clonestr("{\"error\":\"cant find txid\"}")); -} - -STRING_ARG(bitcoinrpc,decoderawtransaction,rawtx) -{ - cJSON *txobj = 0; bits256 txid; - if ( rawtx != 0 && rawtx[0] != 0 ) - { - if ( (strlen(rawtx) & 1) != 0 ) - return(clonestr("{\"error\":\"rawtx hex has odd length\"}")); - txobj = bitcoin_hex2json(coin,&txid,0,rawtx); - //char str[65]; printf("got txid.(%s)\n",bits256_str(str,txid)); - } - if ( txobj == 0 ) - txobj = cJSON_CreateObject(); - return(jprint(txobj,1)); -} - -HASH_ARG(bitcoinrpc,gettransaction,txid) -{ - return(bitcoinrpc_getrawtransaction(IGUANA_CALLARGS,txid,1)); -} - ZERO_ARGS(bitcoinrpc,getbestblockhash) { cJSON *retjson = cJSON_CreateObject(); @@ -219,340 +175,6 @@ ZERO_ARGS(bitcoinrpc,getblockcount) return(jprint(retjson,1)); } -ZERO_ARGS(bitcoinrpc,makekeypair) -{ - bits256 privkey; char str[67]; cJSON *retjson = cJSON_CreateObject(); - privkey = rand256(1); - jaddstr(retjson,"result","success"); - jaddstr(retjson,"privkey",bits256_str(str,privkey)); - jadd(retjson,"rosetta",SuperNET_rosettajson(privkey,1)); - return(jprint(retjson,1)); -} - -STRING_ARG(bitcoinrpc,validatepubkey,pubkeystr) -{ - uint8_t rmd160[20],pubkey[65],addrtype = 0; int32_t plen; char coinaddr[128],*str; cJSON *retjson; - plen = (int32_t)strlen(pubkeystr) >> 1; - if ( plen <= 65 && coin != 0 && coin->chain != 0 ) - { - addrtype = coin->chain->pubtype; - decode_hex(pubkey,plen,pubkeystr); - if ( (str= bitcoin_address(coinaddr,addrtype,pubkey,plen)) != 0 ) - { - if ( iguana_addressvalidate(coin,&addrtype,rmd160,coinaddr) < 0 ) - return(clonestr("{\"error\":\"invalid coin address\"}")); - retjson = cJSON_CreateObject(); - jaddstr(retjson,"result","success"); - jaddstr(retjson,"pubkey",pubkeystr); - jaddstr(retjson,"address",coinaddr); - jaddstr(retjson,"coin",coin->symbol); - return(jprint(retjson,1)); - } - } - return(clonestr("{\"error\":\"invalid pubkey\"}")); -} - -cJSON *iguana_scriptobj(struct iguana_info *coin,uint8_t rmd160[20],char *coinaddr,char *asmstr,uint8_t *script,int32_t scriptlen) -{ - struct vin_info V; int32_t i,plen,asmtype; char pubkeystr[130],rmdstr[41]; cJSON *addrobj,*scriptobj=0; - if ( (asmtype= iguana_calcrmd160(coin,asmstr,&V,script,scriptlen,rand256(1),1,0xffffffff)) >= 0 ) - { - if ( asmstr != 0 && asmstr[0] != 0 ) - jaddstr(scriptobj,"asm",asmstr); - jaddnum(scriptobj,"iguanatype",asmtype); - jaddnum(scriptobj,"scriptlen",scriptlen); - jaddnum(scriptobj,"reqSigs",V.M); - if ( (plen= bitcoin_pubkeylen(V.signers[0].pubkey)) > 0 ) - { - init_hexbytes_noT(pubkeystr,V.signers[0].pubkey,plen); - jaddstr(scriptobj,"pubkey",pubkeystr); - init_hexbytes_noT(rmdstr,V.signers[0].rmd160,20); - jaddstr(scriptobj,"rmd160",rmdstr); - } - addrobj = cJSON_CreateArray(); - for (i=0; i>1) < sizeof(script) ) - { - decode_hex(script,scriptlen,scriptstr); - if ( (scriptobj= iguana_scriptobj(coin,rmd160,coinaddr,asmstr,script,scriptlen)) != 0 ) - jadd(retjson,"result",scriptobj); - } - return(jprint(retjson,1)); -} - -HASH_AND_TWOINTS(bitcoinrpc,gettxout,txid,vout,mempool) -{ - uint8_t script[IGUANA_MAXSCRIPTSIZE],rmd160[20],pubkey33[33]; char coinaddr[128],asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; struct iguana_bundle *bp; int32_t minconf,scriptlen,unspentind,height,spentheight; int64_t RTspend; struct iguana_ramchaindata *rdata; struct iguana_pkhash *P; struct iguana_txid *T; struct iguana_unspent *U; struct iguana_ramchain *ramchain; cJSON *scriptobj,*retjson = cJSON_CreateObject(); - if ( coin != 0 ) - { - minconf = (mempool != 0) ? 0 : 1; - if ( (unspentind= iguana_unspentindfind(coin,&height,txid,vout,coin->bundlescount-1)) != 0 ) - { - if ( height >= 0 && height < coin->longestchain && (bp= coin->bundles[height / coin->chain->bundlesize]) != 0 ) - { - ramchain = (bp == coin->current) ? &coin->RTramchain : &bp->ramchain; - if ( (rdata= ramchain->H.data) != 0 ) - { - U = (void *)(long)((long)rdata + rdata->Uoffset); - P = (void *)(long)((long)rdata + rdata->Poffset); - T = (void *)(long)((long)rdata + rdata->Toffset); - RTspend = 0; - if ( iguana_spentflag(coin,&RTspend,&spentheight,ramchain,bp->hdrsi,unspentind,height,minconf,coin->longestchain,U[unspentind].value) == 0 ) - { - jaddbits256(retjson,"bestblock",coin->blocks.hwmchain.RO.hash2); - jaddnum(retjson,"bestheight",coin->blocks.hwmchain.height); - jaddnum(retjson,"height",height); - jaddnum(retjson,"confirmations",coin->blocks.hwmchain.height - height + 1); - jaddnum(retjson,"value",dstr(U[unspentind].value)); - memset(rmd160,0,sizeof(rmd160)); - memset(pubkey33,0,sizeof(pubkey33)); - memset(coinaddr,0,sizeof(coinaddr)); - if ( (scriptlen= iguana_voutscript(coin,bp,script,0,&U[unspentind],&P[U[unspentind].pkind],vout)) > 0 ) - { - if ( (scriptobj= iguana_scriptobj(coin,rmd160,coinaddr,asmstr,script,scriptlen)) != 0 ) - jadd(retjson,"scriptPubKey",scriptobj); - } - jadd(retjson,"iguana",iguana_unspentjson(myinfo,coin,bp->hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33)); - if ( (height % coin->chain->bundlesize) == 0 && vout == 0 ) - jadd(retjson,"coinbase",jtrue()); - else jadd(retjson,"coinbase",jfalse()); - } - else - { - jaddstr(retjson,"error","already spent"); - jaddnum(retjson,"spentheight",spentheight); - jaddnum(retjson,"unspentind",unspentind); - } - } - } - } - } - return(jprint(retjson,1)); -} - -TWO_STRINGS(bitcoinrpc,signmessage,address,messagestr) -{ - bits256 privkey; int32_t n,len,siglen; char sigstr[256],sig64str[256]; uint8_t sig[128],*message=0; cJSON *retjson = cJSON_CreateObject(); - if ( coin != 0 ) - { - privkey = iguana_str2priv(myinfo,coin,address); - if ( bits256_nonz(privkey) != 0 ) - { - n = (int32_t)strlen(messagestr) >> 1; - if ( messagestr[0] == '0' && messagestr[1] == 'x' && is_hexstr(messagestr+2,n-2) > 0 ) - { - message = malloc(n-2); - decode_hex(message,n-2,messagestr+2); - n -= 2; - } else message = (uint8_t *)messagestr, n <<= 1; - if ( (siglen= bitcoin_sign(sig,sizeof(sig),message,n,privkey)) > 0 ) - { - sigstr[0] = sig64str[0] = 0; - //init_hexbytes_noT(sigstr,sig,siglen); - len = nn_base64_encode(sig,siglen,sig64str,sizeof(sig64str)); - sig64str[len++] = '='; - sig64str[len++] = 0; - jaddstr(retjson,"result",sig64str); - } - if ( message != (void *)messagestr ) - free(message); - } else jaddstr(retjson,"error","invalid address (can be wif, wallet address or privkey hex)"); - } - return(jprint(retjson,1)); -} - -THREE_STRINGS(bitcoinrpc,verifymessage,address,sig,message) -{ - cJSON *retjson = cJSON_CreateObject(); - return(jprint(retjson,1)); -} - -// tx -ARRAY_OBJ_INT(bitcoinrpc,createrawtransaction,vins,vouts,locktime) -{ - bits256 txid; int32_t vout,offset,scriptlen=0,p2shlen=0,i,n; uint32_t sequenceid; uint8_t addrtype,rmd160[20],script[IGUANA_MAXSCRIPTSIZE],redeemscript[IGUANA_MAXSCRIPTSIZE]; uint64_t satoshis; char *hexstr,*str,*field,*txstr; cJSON *txobj,*item,*obj,*retjson = cJSON_CreateObject(); - if ( coin != 0 && (txobj= bitcoin_createtx(coin,locktime)) != 0 ) - { - if ( (n= cJSON_GetArraySize(vins)) > 0 ) - { - for (i=0; i> 1; - decode_hex(script,scriptlen,str); - } - if ( (str= jstr(item,"redeemScript")) != 0 ) - { - p2shlen = (int32_t)strlen(str) >> 1; - decode_hex(redeemscript,p2shlen,str); - } - vout = jint(item,"vout"); - if ( jobj(item,"sequenceid") != 0 ) - sequenceid = juint(item,"sequenceid"); - else sequenceid = 0xffffffff; - txid = jbits256(item,"txid"); - bitcoin_addinput(coin,txobj,txid,vout,sequenceid,script,scriptlen,redeemscript,p2shlen); - } - } - if ( (n= cJSON_GetArraySize(vouts)) > 0 ) - { - item = vouts->child; - while ( item != 0 ) - { - if ( (field= jfieldname(item)) != 0 ) - { - if ( strcmp(field,"data") == 0 ) - { - if ( (hexstr= jstr(item,"data")) != 0 ) - { - scriptlen = (int32_t)strlen(hexstr) >> 1; - offset = 0; - if ( is_hexstr(hexstr,scriptlen) > 0 ) - { - decode_hex(script+4,scriptlen,hexstr); - script[3] = SCRIPT_OPRETURN; - scriptlen++; - /* 1-75 0x01-0x4b (special) data The next opcode bytes is data to be pushed onto the stack - OP_PUSHDATA1 76 0x4c (special) data The next byte contains the number of bytes to be pushed onto the stack. - OP_PUSHDATA2 77 0x4d*/ - if ( scriptlen < 76 ) - { - script[2] = scriptlen; - offset = 2; - scriptlen++; - } - else if ( scriptlen <= 0xff ) - { - script[2] = scriptlen; - script[1] = 0x4c; - offset = 1; - scriptlen += 2; - } - else if ( scriptlen <= 0xffff ) - { - script[2] = ((scriptlen >> 8) & 0xff); - script[1] = (scriptlen & 0xff); - script[0] = 0x4d; - offset = 0; - scriptlen += 3; - } - else continue; - if ( (obj= jobj(item,"amount")) != 0 ) - satoshis = get_API_float(obj) * SATOSHIDEN; - else satoshis = 0; - bitcoin_addoutput(coin,txobj,script+offset,scriptlen,satoshis); - } - } - break; - } - else - { - if ( bitcoin_addr2rmd160(&addrtype,rmd160,field) == sizeof(rmd160) ) - { - scriptlen = bitcoin_standardspend(script,0,rmd160); - satoshis = get_API_float(item) * SATOSHIDEN; - bitcoin_addoutput(coin,txobj,script,scriptlen,satoshis); - } - } - } - item = item->next; - } - } - if ( (txstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 ) - { - jaddstr(retjson,"result",txstr); - free(txstr); - } - } - return(jprint(retjson,1)); -} - -/*struct bitcoin_unspent -{ - bits256 txid,privkeys[16]; uint64_t value; int32_t vout,spendlen,p2shlen; uint32_t sequence; - uint8_t addrtype,rmd160[20],pubkey[65],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE]; -}; - -struct bitcoin_spend -{ - char changeaddr[64]; uint8_t change160[20]; - int32_t numinputs; - int64_t txfee,input_satoshis,satoshis,change; - struct bitcoin_unspent inputs[]; -};*/ - -STRING_ARRAY_OBJ_STRING(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys,sighash) -{ - bits256 txid; char *privkeystr,*signedtx = 0; bits256 privkey; int32_t i,n,numinputs = 1; struct bitcoin_spend *spend; cJSON *txobj=0,*item,*retjson = cJSON_CreateObject(); - //printf("rawtx.(%s) vins.(%s) privkeys.(%s) sighash.(%s)\n",rawtx,jprint(vins,0),jprint(privkeys,0),sighash); - if ( sighash == 0 || sighash[0] == 0 ) - sighash = "ALL"; - if ( strcmp(sighash,"ALL") != 0 ) - jaddstr(retjson,"error","only sighash all supported for now"); - else - { - // need to mix and match privkeys with inputs[i] - signedtx = clonestr(rawtx); - if ( (numinputs= cJSON_GetArraySize(vins)) > 0 && (n= cJSON_GetArraySize(privkeys)) > 0 ) - { - spend = calloc(1,sizeof(*spend) + (sizeof(*spend->inputs) * numinputs)); - spend->numinputs = numinputs; - for (i=0; iinputs[0].privkeys[i] = privkey; - //if ( i < numinputs ) - // spend->inputs[i].privkeys[0] = privkey; - char str2[65]; printf("privkey.%s <- %s\n",bits256_str(str2,privkey),privkeystr); - } - } - txobj = iguana_signtx(coin,&txid,&signedtx,spend,txobj); - free(spend); - free_json(txobj); - if ( signedtx != 0 ) - { - jaddstr(retjson,"result",signedtx); - free(signedtx); - } - } - } - return(jprint(retjson,1)); -} - -TWOINTS_AND_ARRAY(bitcoinrpc,listunspent,minconf,maxconf,array) -{ - int32_t numrmds; uint8_t *rmdarray; cJSON *retjson = cJSON_CreateArray(); - if ( minconf == 0 ) - minconf = 1; - if ( maxconf == 0 ) - maxconf = 9999999; - rmdarray = iguana_rmdarray(coin,&numrmds,array,0); - iguana_unspents(myinfo,coin,retjson,minconf,maxconf,rmdarray,numrmds,0); - if ( rmdarray != 0 ) - free(rmdarray); - return(jprint(retjson,1)); -} - STRING_AND_INT(iguana,bundleaddresses,activecoin,height) { struct iguana_info *ptr; @@ -585,19 +207,31 @@ STRING_AND_INT(iguana,bundlehashes,activecoin,height) } // low priority RPC -ZERO_ARGS(bitcoinrpc,gettxoutsetinfo) -{ - cJSON *retjson = cJSON_CreateObject(); - return(jprint(retjson,1)); -} -INT_AND_ARRAY(bitcoinrpc,lockunspent,flag,array) +HASH_AND_TWOINTS(bitcoinrpc,listsinceblock,blockhash,target,flag) { + /*"transactions" : [ + { + "account" : "doc test", + "address" : "mmXgiR6KAhZCyQ8ndr2BCfEq1wNG2UnyG6", + "category" : "receive", + "amount" : 0.10000000, + "vout" : 0, + "confirmations" : 76478, + "blockhash" : "000000000017c84015f254498c62a7c884a51ccd75d4dd6dbdcb6434aa3bd44d", + "blockindex" : 1, + "blocktime" : 1399294967, + "txid" : "85a98fdf1529f7d5156483ad020a51b7f3340e47448cf932f470b72ff01a6821", + "walletconflicts" : [ + ], + "time" : 1399294967, + "timereceived" : 1418924714 + },*/ cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); } -ZERO_ARGS(bitcoinrpc,listlockunspent) +ZERO_ARGS(bitcoinrpc,gettxoutsetinfo) { cJSON *retjson = cJSON_CreateObject(); return(jprint(retjson,1)); @@ -616,6 +250,43 @@ ZERO_ARGS(bitcoinrpc,getrawchangeaddress) return(jprint(retjson,1)); } +SS_D_I_S(bitcoinrpc,move,fromaccount,toaccount,amount,minconf,comment) +{ + cJSON *retjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + retjson = cJSON_CreateObject(); + return(jprint(retjson,1)); +} + +ZERO_ARGS(bitcoinrpc,checkwallet) +{ + cJSON *retjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + return(jprint(retjson,1)); +} + +ZERO_ARGS(bitcoinrpc,repairwallet) +{ + cJSON *retjson; + if ( remoteaddr != 0 ) + return(clonestr("{\"error\":\"no remote\"}")); + if ( myinfo->expiration == 0 ) + return(clonestr("{\"error\":\"need to unlock wallet\"}")); + myinfo->expiration++; + retjson = cJSON_CreateObject(); + jaddstr(retjson,"result","success"); + return(jprint(retjson,1)); +} + #undef IGUANA_ARGS #include "../includes/iguana_apiundefs.h" diff --git a/iguana/swaps/iguana_BTCswap.c b/iguana/swaps/iguana_BTCswap.c index 893944470..be809a96c 100755 --- a/iguana/swaps/iguana_BTCswap.c +++ b/iguana/swaps/iguana_BTCswap.c @@ -92,6 +92,16 @@ void disp_tx(struct supernet_info *myinfo,struct iguana_info *coin,char *str,cha printf("disp_tx (%s) -> %s.(%s)\n",txbytes,str,jprint(txobj,1)); } +void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON *txobj,uint32_t sequence) +{ + int32_t i; + for (i=0; inuminputs; i++) + { + spend->inputs[i].sequence = sequence; + bitcoin_addinput(coin,txobj,spend->inputs[i].txid,spend->inputs[i].vout,spend->inputs[i].sequence,spend->inputs[i].spendscript,spend->inputs[i].spendlen,spend->inputs[i].p2shscript,spend->inputs[i].p2shlen); + } +} + struct bitcoin_statetx *instantdex_feetx(struct supernet_info *myinfo,struct instantdex_accept *A) { int32_t n,len; char *feetx = 0; struct iguana_info *coin; bits256 txid; cJSON *txobj; struct bitcoin_spend *spend; int64_t insurance; uint8_t paymentscript[128]; struct bitcoin_statetx *ptr = 0; diff --git a/iguana/tests/sendmany b/iguana/tests/sendmany new file mode 100755 index 000000000..957b6866a --- /dev/null +++ b/iguana/tests/sendmany @@ -0,0 +1 @@ +curl --url "http://127.0.0.1:7778" --data "{\"method\":\"sendmany\", \"params\":[\"\", {\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\":0.01, \"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\":0.02}, 2]}" diff --git a/iguana/tests/sendtoaddress b/iguana/tests/sendtoaddress new file mode 100755 index 000000000..89d780cd3 --- /dev/null +++ b/iguana/tests/sendtoaddress @@ -0,0 +1,2 @@ +curl --url "http://127.0.0.1:7778" --data "{\"method\":\"sendtoaddress\",\"params\":[\"17outUgtsnLkguDuXm14tcQ7dMbdD8KZGK\", 0.001]}" + diff --git a/includes/iguana_apideclares.h b/includes/iguana_apideclares.h index 8e95baeee..73238035f 100755 --- a/includes/iguana_apideclares.h +++ b/includes/iguana_apideclares.h @@ -59,28 +59,28 @@ TWO_STRINGS(bitcoinrpc,setaccount,address,account); INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,pubkeys,ignore); INT_ARRAY_STRING(bitcoinrpc,addmultisigaddress,M,pubkeys,account); +DOUBLE_ARG(bitcoinrpc,settxfee,amount); -STRING_ARRAY_OBJ_STRING(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys,sighash); // +STRING_ARG(bitcoinrpc,submitblock,rawbytes); STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees); // -SS_D_I_S(bitcoinrpc,move,fromaccount,toaccount,amount,minconf,comment); // -SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2); // -S_A_I_S(bitcoinrpc,sendmany,fromaccount,array,minconf,comment); // -S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2); // -DOUBLE_ARG(bitcoinrpc,settxfee,amount); - -HASH_AND_TWOINTS(bitcoinrpc,listsinceblock,blockhash,target,flag); // +STRING_ARRAY_OBJ_STRING(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys,sighash); // TWO_STRINGS(bitcoinrpc,signmessage,address,message); // THREE_STRINGS(bitcoinrpc,verifymessage,address,sig,message); // -// maybe later +SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2); // +S_A_I_S(bitcoinrpc,sendmany,fromaccount,payments,minconf,comment); // +S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2); // +// maybe later +HASH_AND_TWOINTS(bitcoinrpc,listsinceblock,blockhash,target,flag); ZERO_ARGS(bitcoinrpc,gettxoutsetinfo); INT_AND_ARRAY(bitcoinrpc,lockunspent,flag,array); ZERO_ARGS(bitcoinrpc,listlockunspent); ZERO_ARGS(bitcoinrpc,getrawchangeaddress); ZERO_ARGS(bitcoinrpc,checkwallet); ZERO_ARGS(bitcoinrpc,repairwallet); +SS_D_I_S(bitcoinrpc,move,fromaccount,toaccount,amount,minconf,comment); STRING_ARG(iguana,initfastfind,activecoin); STRING_ARG(iguana,peers,activecoin);