diff --git a/iguana/iguana777.h b/iguana/iguana777.h index 57eb016f6..94447ba8f 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -972,6 +972,9 @@ void instantdex_update(struct supernet_info *myinfo); cJSON *iguana_getaddressesbyaccount(struct supernet_info *myinfo,struct iguana_info *coin,char *account); int32_t iguana_interpreter(struct iguana_info *coin,cJSON *logarray,int64_t nLockTime,struct vin_info *V,int32_t numvins); int32_t iguana_parsevinobj(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvin *vin,cJSON *vinobj,struct vin_info *V); +int64_t iguana_availunspents(struct supernet_info *myinfo,uint64_t **unspentsp,int32_t *nump,struct iguana_info *coin,int32_t minconf,char *account,void *ptr,int32_t maxsize); +char *iguana_signunspents(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *signedtxidp,int32_t *completedp,cJSON *txobj,uint64_t satoshis,char *changeaddr,uint64_t txfee,uint64_t *unspents,int32_t num); +bits256 iguana_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *signedtx); extern int32_t HDRnet,netBLOCKS; diff --git a/iguana/iguana_interpreter.c b/iguana/iguana_interpreter.c index 902549602..cd29f2d9e 100755 --- a/iguana/iguana_interpreter.c +++ b/iguana/iguana_interpreter.c @@ -705,12 +705,12 @@ int32_t iguana_checksig(struct iguana_info *coin,struct iguana_stackdata pubkeya uint8_t pubkey[MAX_SCRIPT_ELEMENT_SIZE],sig[MAX_SCRIPT_ELEMENT_SIZE]; int32_t plen,siglen; plen = iguana_databuf(pubkey,pubkeyarg); siglen = iguana_databuf(sig,sigarg); - int32_t i; for (i=0; i 0 && siglen > 0 && siglen < 74 ) return(bitcoin_verify(coin->ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0); return(0); diff --git a/iguana/iguana_payments.c b/iguana/iguana_payments.c index 473d90c3f..810913a24 100755 --- a/iguana/iguana_payments.c +++ b/iguana/iguana_payments.c @@ -241,7 +241,7 @@ cJSON *iguana_inputsjson(struct supernet_info *myinfo,struct iguana_info *coin,i jaddi(vins,item); total += value; remains -= value; - printf("value %.8f -> remains %.8f\n",dstr(value),dstr(remains)); + printf("%s value %.8f -> remains %.8f\n",coinaddr,dstr(value),dstr(remains)); if ( remains <= 0 ) break; } @@ -270,11 +270,11 @@ cJSON *iguana_inputsjson(struct supernet_info *myinfo,struct iguana_info *coin,i return(vins); } -char *iguana_signunspents(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *completedp,char *coinaddr,uint64_t satoshis,char *changeaddr,uint64_t txfee,uint64_t *unspents,int32_t num) +char *iguana_signunspents(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *signedtxidp,int32_t *completedp,cJSON *txobj,uint64_t satoshis,char *changeaddr,uint64_t txfee,uint64_t *unspents,int32_t num) { - uint8_t addrtype,rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE]; uint32_t locktime = 0; int32_t spendlen,numinputs,i,RTspentflag; struct iguana_msgtx msgtx; char *rawtx=0,*signedtx = 0; bits256 txid,signedtxid; cJSON *txobj,*vins=0,*privkeys=0; struct vin_info *V; int64_t value,total,change; char changeaddress[64]; struct iguana_waddress *waddr; + uint8_t addrtype,rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE]; int32_t spendlen,numinputs,i,RTspentflag; struct iguana_msgtx msgtx; char *rawtx=0,*signedtx = 0; bits256 txid; cJSON *vins=0,*privkeys=0; struct vin_info *V; int64_t value,total,change; char changeaddress[64]; struct iguana_waddress *waddr; *completedp = 0; - if ( (vins= iguana_inputsjson(myinfo,coin,&total,satoshis + txfee,unspents,num)) != 0 ) + if ( txobj != 0 && (vins= iguana_inputsjson(myinfo,coin,&total,satoshis + txfee,unspents,num)) != 0 ) { if ( total < (satoshis + txfee) ) { @@ -297,51 +297,38 @@ char *iguana_signunspents(struct supernet_info *myinfo,struct iguana_info *coin, } if ( (privkeys= iguana_privkeysjson(myinfo,coin,vins)) != 0 ) { - if ( (txobj= bitcoin_txcreate(coin,locktime)) != 0 ) + iguana_createvins(myinfo,coin,txobj,vins); + if ( change > 0 ) { - iguana_createvins(myinfo,coin,txobj,vins); - if ( iguana_addressvalidate(coin,&addrtype,coinaddr) < 0 ) + if ( iguana_addressvalidate(coin,&addrtype,changeaddr) < 0 ) { free_json(vins), free_json(privkeys), free_json(txobj); - printf("illegal destination address.(%s)\n",coinaddr); + printf("illegal destination address.(%s)\n",changeaddr); return(0); } - bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); + bitcoin_addr2rmd160(&addrtype,rmd160,changeaddr); spendlen = bitcoin_standardspend(spendscript,0,rmd160); - bitcoin_txoutput(coin,txobj,spendscript,spendlen,satoshis); - if ( change > 0 ) - { - if ( iguana_addressvalidate(coin,&addrtype,changeaddr) < 0 ) - { - free_json(vins), free_json(privkeys), free_json(txobj); - printf("illegal destination address.(%s)\n",changeaddr); - return(0); - } - bitcoin_addr2rmd160(&addrtype,rmd160,changeaddr); - spendlen = bitcoin_standardspend(spendscript,0,rmd160); - bitcoin_txoutput(coin,txobj,spendscript,spendlen,change); - } - if ( (rawtx= bitcoin_json2hex(myinfo,coin,&txid,txobj,0)) != 0 ) + bitcoin_txoutput(coin,txobj,spendscript,spendlen,change); + } + if ( (rawtx= bitcoin_json2hex(myinfo,coin,&txid,txobj,0)) != 0 ) + { + if ( (numinputs= cJSON_GetArraySize(vins)) > 0 && (V= calloc(numinputs,sizeof(*V))) != 0 ) { - if ( (numinputs= cJSON_GetArraySize(vins)) > 0 && (V= calloc(numinputs,sizeof(*V))) != 0 ) + memset(&msgtx,0,sizeof(msgtx)); + if ( iguana_signrawtransaction(myinfo,coin,&msgtx,&signedtx,signedtxidp,V,numinputs,rawtx,vins,privkeys) > 0 ) { - memset(&msgtx,0,sizeof(msgtx)); - if ( iguana_signrawtransaction(myinfo,coin,&msgtx,&signedtx,&signedtxid,V,numinputs,rawtx,vins,privkeys) > 0 ) + for (i=0; i> 32),(uint32_t)unspents[i << 1],&RTspentflag,1); - } - *completedp = 1; + value = unspents[(i << 1) + 1]; + if ( value == -1 ) + iguana_utxofind(coin,(int32_t)(unspents[i << 1] >> 32),(uint32_t)unspents[i << 1],&RTspentflag,1); } - else printf("signrawtransaction incomplete\n"); - free(V); + *completedp = 1; } - free(rawtx); + else printf("signrawtransaction incomplete\n"); + free(V); } - free_json(txobj); + free(rawtx); } free_json(privkeys); } @@ -350,48 +337,89 @@ char *iguana_signunspents(struct supernet_info *myinfo,struct iguana_info *coin, return(signedtx); } -char *sendtoaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,uint64_t satoshis,uint64_t txfee,char *comment,char *comment2,int32_t minconf,char *account) +int64_t iguana_availunspents(struct supernet_info *myinfo,uint64_t **unspentsp,int32_t *nump,struct iguana_info *coin,int32_t minconf,char *account,void *ptr,int32_t maxsize) { - uint8_t addrtype; int32_t i,j,num,completed,numwaddrs; struct iguana_waddress **waddrs,*waddr; uint64_t *unspents,value,avail=0; char *signedtx = 0; cJSON *retjson; - //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 && satoshis != 0 ) + int32_t i,j,num,numwaddrs; struct iguana_waddress **waddrs,*waddr; uint64_t *unspents,value,avail=0; + *unspentsp = unspents = 0; + *nump = num = 0; + waddrs = (struct iguana_waddress **)ptr; + numwaddrs = iguana_unspentslists(myinfo,coin,waddrs,(int32_t)(maxsize/sizeof(*waddrs)),(uint64_t)1 << 62,minconf,account); + if ( numwaddrs > 0 ) { - if ( iguana_addressvalidate(coin,&addrtype,coinaddr) < 0 ) - return(clonestr("{\"error\":\"invalid coin address\"}")); - waddrs = (struct iguana_waddress **)coin->blockspace; - numwaddrs = iguana_unspentslists(myinfo,coin,waddrs,(int32_t)(sizeof(coin->blockspace)/sizeof(*waddrs)),(uint64_t)1 << 62,minconf,account); - if ( numwaddrs > 0 ) + unspents = (uint64_t *)((long)ptr + sizeof(*waddrs)*numwaddrs); + for (i=num=0; iblockspace + sizeof(*waddrs)*numwaddrs); - for (i=num=0; inumunspents > 0 ) { - if ( (waddr= waddrs[i]) != 0 && waddr->numunspents > 0 ) + for (j=0; jnumunspents; j++) { - for (j=0; jnumunspents; j++) + if ( (value= iguana_unspentavail(coin,waddr->unspents[j],minconf,coin->longestchain)) != 0 ) { - if ( (value= iguana_unspentavail(coin,waddr->unspents[j],minconf,coin->longestchain)) != 0 ) - { - unspents[num << 1] = waddr->unspents[j]; - unspents[(num << 1) + 1] = value; - num++; - avail += value; - printf("([%d].u%u) ",(uint32_t)(waddr->unspents[j]>>32),(uint32_t)waddr->unspents[j]); - } + unspents[num << 1] = waddr->unspents[j]; + unspents[(num << 1) + 1] = value; + num++; + avail += value; + printf("([%d].u%u) ",(uint32_t)(waddr->unspents[j]>>32),(uint32_t)waddr->unspents[j]); } - printf("(%s %.8f)\n",waddr->coinaddr,dstr(waddr->balance)); } + printf("(%s %.8f)\n",waddr->coinaddr,dstr(waddr->balance)); } - if ( avail < satoshis+txfee ) - return(clonestr("{\"error\":\"not enough funds\"}")); - else if ( (signedtx= iguana_signunspents(myinfo,coin,&completed,coinaddr,satoshis,coin->changeaddr,txfee,unspents,num)) != 0 ) + } + } + *unspentsp = unspents; + *nump = num; + return(avail); +} + +bits256 iguana_sendrawtransaction(struct supernet_info *myinfo,struct iguana_info *coin,char *signedtx) +{ + bits256 txid; uint8_t *serialized; int32_t i,len; struct iguana_peer *addr; + if ( coin->peers.numranked >= 8 ) + { + len = (int32_t)strlen(signedtx) >> 1; + serialized = calloc(1,sizeof(struct iguana_msghdr) + len); + decode_hex(&serialized[sizeof(struct iguana_msghdr)],len,signedtx); + for (i=0; i<8; i++) + { + if ( (addr= coin->peers.ranked[i]) != 0 && addr->dead == 0 && addr->usock >= 0 ) + iguana_queue_send(coin,addr,0,serialized,"tx",len,0,0); + } + free(serialized); + txid = bits256_doublesha256(0,&serialized[sizeof(struct iguana_msghdr)],len); + } else memset(txid.bytes,0,sizeof(txid)); + return(txid); +} + +char *sendtoaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,uint64_t satoshis,uint64_t txfee,char *comment,char *comment2,int32_t minconf,char *account) +{ + uint8_t addrtype,rmd160[20],spendscript[4096]; int32_t spendlen,num,completed; uint64_t *unspents,avail=0; char *signedtx = 0; bits256 signedtxid,senttxid; cJSON *retjson,*txobj; uint32_t locktime = 0; + //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 && satoshis != 0 ) + { + if ( iguana_addressvalidate(coin,&addrtype,coinaddr) < 0 ) + return(clonestr("{\"error\":\"invalid coin address\"}")); + bitcoin_addr2rmd160(&addrtype,rmd160,coinaddr); + spendlen = bitcoin_standardspend(spendscript,0,rmd160); + avail = iguana_availunspents(myinfo,&unspents,&num,coin,minconf,account,coin->blockspace,sizeof(coin->blockspace)); + if ( avail < satoshis+txfee || unspents == 0 || num <= 0 ) + return(clonestr("{\"error\":\"not enough funds\"}")); + else if ( (txobj= bitcoin_txcreate(coin,locktime)) != 0 ) + { + bitcoin_txoutput(coin,txobj,spendscript,spendlen,satoshis); + if ( (signedtx= iguana_signunspents(myinfo,coin,&signedtxid,&completed,txobj,satoshis,coin->changeaddr,txfee,unspents,num)) != 0 ) { retjson = cJSON_CreateObject(); - jaddstr(retjson,"result",signedtx); + jaddbits256(retjson,"result",signedtxid); + jaddstr(retjson,"signedtx",signedtx); jadd(retjson,"complete",completed != 0 ? jtrue() : jfalse()); + senttxid = iguana_sendrawtransaction(myinfo,coin,signedtx); + if ( bits256_cmp(senttxid,signedtxid) == 0 ) + jaddstr(retjson,"sendrawtransaction","success"); + else jaddbits256(retjson,"senderror",senttxid); free(signedtx); return(jprint(retjson,1)); } else return(clonestr("{\"error\":\"couldnt create signedtx\"}")); - } else return(clonestr("{\"error\":\"no funded wallet addresses\"}")); + } else return(clonestr("{\"error\":\"couldnt create txobj\"}")); } return(clonestr("{\"error\":\"need address and amount\"}")); } @@ -401,22 +429,11 @@ char *sendtoaddress(struct supernet_info *myinfo,struct iguana_info *coin,char * STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees) { - cJSON *retjson = cJSON_CreateObject(); char txidstr[65]; bits256 txid; uint8_t *serialized; struct iguana_peer *addr; int32_t i,len = (int32_t)strlen(rawtx) >> 1; + cJSON *retjson = cJSON_CreateObject(); bits256 txid; if ( remoteaddr != 0 ) return(clonestr("{\"error\":\"no remote\"}")); - if ( coin->peers.numranked >= 8 ) - { - serialized = calloc(1,sizeof(struct iguana_msghdr) + len); - decode_hex(&serialized[sizeof(struct iguana_msghdr)],len,rawtx); - for (i=0; i<8; i++) - { - if ( (addr= coin->peers.ranked[i]) != 0 && addr->dead == 0 && addr->usock >= 0 ) - iguana_queue_send(coin,addr,0,serialized,"tx",len,0,0); - } - free(serialized); - txid = bits256_doublesha256(txidstr,&serialized[sizeof(struct iguana_msghdr)],len); - jaddstr(retjson,"result",txidstr); - } else jaddstr(retjson,"error","no peers"); + txid = iguana_sendrawtransaction(myinfo,coin,rawtx); + jaddbits256(retjson,"result",txid); return(jprint(retjson,1)); } @@ -812,7 +829,7 @@ STRING_ARG(bitcoinrpc,validaterawtransaction,rawtx) V[i].suffixlen = suffixlen; memcpy(V[i].spendscript,msgtx.vins[i].spendscript,msgtx.vins[i].spendlen); V[i].spendlen = msgtx.vins[i].spendlen; - printf("V %.8f (%s) spendscript.[%d] scriptlen.%d\n",dstr(V[i].amount),V[i].coinaddr,V[i].spendlen,V[i].spendlen); + //printf("V %.8f (%s) spendscript.[%d] scriptlen.%d\n",dstr(V[i].amount),V[i].coinaddr,V[i].spendlen,V[i].spendlen); } } if ( (complete= bitcoin_verifyvins(coin,&signedtxid,&signedtx,&msgtx,serialized2,maxsize,V,1)) > 0 && signedtx != 0 ) diff --git a/iguana/iguana_sign.c b/iguana/iguana_sign.c index 100554eb3..9fbe708c9 100755 --- a/iguana/iguana_sign.c +++ b/iguana/iguana_sign.c @@ -166,7 +166,7 @@ int32_t iguana_parsevinobj(struct supernet_info *myinfo,struct iguana_info *coin { memcpy(V->signers[0].pubkey,waddr->pubkey,bitcoin_pubkeylen(waddr->pubkey)); } - printf("V %.8f (%s) spendscript.[%d]\n",dstr(V->amount),V->coinaddr,V->spendlen); + //printf("V %.8f (%s) spendscript.[%d]\n",dstr(V->amount),V->coinaddr,V->spendlen); } } if ( (pubkeysjson= jarray(&n,vinobj,"pubkeys")) != 0 ) @@ -680,7 +680,7 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** return(complete); } -int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,char *rawtxstr,struct vin_info *V,int32_t numinputs) +/*int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,char *rawtxstr,struct vin_info *V,int32_t numinputs) { int32_t len,maxsize,retval = -1; uint8_t *serialized,*serialized2; struct iguana_msgtx msgtx; bits256 txid; char vpnstr[64]; @@ -758,11 +758,11 @@ cJSON *iguana_signtx(struct supernet_info *myinfo,struct iguana_info *coin,bits2 memcpy(vp->signers[j].pubkey,spend->inputs[i].pubkeys[j],plen); } } - /*if ( spend->inputs[i].spendlen > 0 ) - { - memcpy(vp->spendscript,spend->inputs[i].spendscript,spend->inputs[i].spendlen); - vp->spendlen = spend->inputs[i].spendlen; - }*/ + //if ( spend->inputs[i].spendlen > 0 ) + // { + // memcpy(vp->spendscript,spend->inputs[i].spendscript,spend->inputs[i].spendlen); + // vp->spendlen = spend->inputs[i].spendlen; + // } if ( spend->inputs[i].p2shlen > 0 ) { memcpy(vp->p2shscript,spend->inputs[i].p2shscript,spend->inputs[i].p2shlen); @@ -797,7 +797,7 @@ cJSON *iguana_signtx(struct supernet_info *myinfo,struct iguana_info *coin,bits2 free(*signedtxp), *signedtxp = 0; free(V); return(txobj); -} +}*/ int32_t iguana_vininfo_create(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msgtx,cJSON *vins,int32_t numinputs,struct vin_info *V) { @@ -820,7 +820,7 @@ int32_t iguana_vininfo_create(struct supernet_info *myinfo,struct iguana_info *c msgtx->vins[i].spendlen = vp->spendlen; vp->hashtype = iguana_vinscriptparse(coin,V,&sigsize,&pubkeysize,&p2shsize,&suffixlen,vp->spendscript,vp->spendlen); vp->suffixlen = suffixlen; - printf("V %.8f (%s) spendscript.[%d]\n",dstr(vp->amount),vp->coinaddr,vp->spendlen); + //printf("V %.8f (%s) spendscript.[%d]\n",dstr(vp->amount),vp->coinaddr,vp->spendlen); } } else diff --git a/iguana/iguana_unspents.c b/iguana/iguana_unspents.c index 65ef98ce4..c2980bc9e 100755 --- a/iguana/iguana_unspents.c +++ b/iguana/iguana_unspents.c @@ -150,7 +150,7 @@ struct iguana_pkhash *iguana_pkhashfind(struct iguana_info *coin,struct iguana_r *ramchainp = ramchain; *depositsp = ACCTS[pkind].total; *lastunspentindp = ACCTS[pkind].lastunspentind; - printf("[%d] return pkind.%u of %u P.%p %.8f last.%u ACCTS.%p %p\n",i,pkind,numpkinds,P,dstr(*depositsp),*lastunspentindp,ACCTS,ramchain->A); + //printf("[%d] return pkind.%u of %u P.%p %.8f last.%u ACCTS.%p %p\n",i,pkind,numpkinds,P,dstr(*depositsp),*lastunspentindp,ACCTS,ramchain->A); if ( P != 0 ) *p = P[pkind]; return(p); @@ -199,7 +199,7 @@ int64_t iguana_pkhashbalance(struct supernet_info *myinfo,struct iguana_info *co if ( lastheight <= 0 || 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 ( iguana_spentflag(coin,&RTspend,&spentheight,ramchain,hdrsi,unspentind,lastheight,minconf,maxconf,U[unspentind].value) == 0 ) { if ( *nump < max && unspents != 0 ) unspents[*nump] = ((uint64_t)hdrsi << 32) | unspentind; @@ -233,7 +233,7 @@ int64_t iguana_pkhashbalance(struct supernet_info *myinfo,struct iguana_info *co 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)); + //printf("(%s) spent %.8f, RTspent %.8f deposits %.8f\n",coinaddr,dstr(spent),dstr(RTspend),dstr(deposits)); return(deposits - spent); } @@ -270,11 +270,13 @@ int32_t iguana_pkhasharray(struct supernet_info *myinfo,struct iguana_info *coin } 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)); + //printf("%s pkhash balance.[%d] from m.%d check %.8f vs %.8f spent %.8f [%.8f]\n",coinaddr,i,m,dstr(netbalance),dstr(deposits),dstr(spent),dstr(deposits)-dstr(spent)); total += netbalance; n++; } maxunspents -= m; + if ( maxunspents <= 0 ) + break; numunspents += m; //printf("%d: balance %.8f, lastunspent.%u m.%d num.%d max.%d\n",i,dstr(total),lastunspentind,m,numunspents,maxunspents); } @@ -360,7 +362,7 @@ int64_t iguana_unspentset(struct supernet_info *myinfo,struct iguana_info *coin) continue; total = 0; n = 0; - 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,&n,(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,&n,(int32_t)(sizeof(coin->blockspace)/sizeof(*waddr->unspents))-1000); if ( n > 0 ) { if ( waddr->unspents == 0 || waddr->maxunspents < n ) diff --git a/iguana/iguana_volatiles.c b/iguana/iguana_volatiles.c index 4e8de60ca..bed0494ef 100755 --- a/iguana/iguana_volatiles.c +++ b/iguana/iguana_volatiles.c @@ -147,7 +147,7 @@ int32_t iguana_spentflag(struct iguana_info *coin,int64_t *RTspendp,int32_t *spe } //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) ) + if ( (confs= coin->blocks.hwmchain.height - utxo.fromheight) >= minconf && confs < maxconf && (height <= 0 || utxo.fromheight < height) ) { (*RTspendp) += RTspend; if ( utxo.spentflag != 0 ) diff --git a/iguana/iguana_wallet.c b/iguana/iguana_wallet.c index ec47345f1..3f191332a 100755 --- a/iguana/iguana_wallet.c +++ b/iguana/iguana_wallet.c @@ -89,7 +89,7 @@ struct iguana_waddress *iguana_waddresscreate(struct supernet_info *myinfo,struc { HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); myinfo->dirty = (uint32_t)time(NULL); - //printf("create (%s).%d scriptlen.%d -> (%s)\n",coinaddr,len,waddr->scriptlen,wacct->account); + printf("create (%s).%d scriptlen.%d -> (%s)\n",coinaddr,len,waddr->scriptlen,wacct->account); } else printf("error iguana_waddressalloc null waddr\n"); } //else printf("have (%s) in (%s)\n",coinaddr,wacct->account); if ( (ptr= iguana_waddressfind(myinfo,coin,wacct,coinaddr)) != waddr ) @@ -103,17 +103,15 @@ 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(redeemScript==0?coin->chain->pubtype : coin->chain->p2shtype,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); - //printf("add (%s).%d scriptlen.%d -> (%s) wif.(%s)\n",waddr->coinaddr,len,waddr->scriptlen,wacct->account,waddr->wifstr); - } else printf("error iguana_waddressalloc null waddr\n"); + printf("error iguana_waddressalloc null waddr\n"); + return(0); + } } //else printf("have (%s) in (%s)\n",waddr->coinaddr,wacct->account); - if ( (ptr= iguana_waddressfind(myinfo,coin,wacct,waddr->coinaddr)) != waddr ) - printf("iguana_waddressadd verify error %p vs %p\n",ptr,waddr); if ( waddr != 0 && waddr != addwaddr ) { + myinfo->dirty = (uint32_t)time(NULL); waddr->wiftype = coin->chain->wiftype; if ( redeemScript != 0 && (addwaddr->scriptlen= (int32_t)strlen(redeemScript) >> 1) != 0 ) { @@ -129,6 +127,7 @@ struct iguana_waddress *iguana_waddressadd(struct supernet_info *myinfo,struct i waddr->addrtype = coin->chain->p2shtype; memset(&waddr->privkey,0,sizeof(waddr->privkey)); memset(waddr->pubkey,0,sizeof(waddr->pubkey)); + calc_rmd160_sha256(waddr->rmd160,waddr->redeemScript,waddr->scriptlen); } else { @@ -139,11 +138,17 @@ struct iguana_waddress *iguana_waddressadd(struct supernet_info *myinfo,struct i if ( addwaddr->wifstr[0] != 0 ) strcpy(waddr->wifstr,addwaddr->wifstr); memcpy(waddr->pubkey,addwaddr->pubkey,sizeof(waddr->pubkey)); + calc_rmd160_sha256(waddr->rmd160,waddr->pubkey,bitcoin_pubkeylen(waddr->pubkey)); } - memcpy(waddr->rmd160,addwaddr->rmd160,sizeof(waddr->rmd160)); - strcpy(waddr->coinaddr,addwaddr->coinaddr); + bitcoin_address(waddr->coinaddr,waddr->addrtype,waddr->rmd160,sizeof(waddr->rmd160)); myinfo->dirty = (uint32_t)time(NULL); } + if ( (ptr= iguana_waddressfind(myinfo,coin,wacct,waddr->coinaddr)) != waddr ) + { + HASH_ADD_KEYPTR(hh,wacct->waddr,waddr->coinaddr,len,waddr); + myinfo->dirty = (uint32_t)time(NULL); + //printf("add (%s).%d scriptlen.%d -> (%s) wif.(%s)\n",waddr->coinaddr,len,waddr->scriptlen,wacct->account,waddr->wifstr); + } if ( waddr != 0 && waddr->symbol[0] == 0 ) strcpy(waddr->symbol,coin->symbol); return(waddr); @@ -182,6 +187,7 @@ struct iguana_waddress *iguana_waddresssearch(struct supernet_info *myinfo,struc return(waddr); } } + (*wacctp) = 0; return(0); } @@ -193,6 +199,7 @@ struct iguana_waddress *iguana_waddresscalc(struct supernet_info *myinfo,uint8_t { bitcoin_pubkey33(myinfo->ctx,waddr->pubkey,waddr->privkey); calc_rmd160_sha256(waddr->rmd160,waddr->pubkey,33); + myinfo->dirty = (uint32_t)time(NULL); if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,wiftype) > 0 ) { waddr->wiftype = wiftype; @@ -564,16 +571,17 @@ int32_t iguana_walletemit(struct supernet_info *myinfo,char *fname,struct iguana } char *walleterrstr[] = { "P2SH_withpriv", "P2SH_withpub", "rmd160_mismatch", "pubkey_mismatch", "missing_pubkey", "account_mismatch" }; + uint8_t iguana_waddrvalidate(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_waccount *wacct,struct iguana_waddress *waddr,int32_t repairflag,int32_t *errors) { - struct iguana_waccount *checkwacct; struct iguana_waddress *checkwaddr; uint8_t checkpub[33],rmd160[20],addrtype,checktype,plen,flag=0; + struct iguana_waccount *checkwacct; struct iguana_waddress *checkwaddr; uint8_t checkpub[33],rmd160[20],addrtype,checktype,plen,flag=0; int32_t i; if ( waddr != 0 ) { if ( (checkwaddr= iguana_waddresssearch(myinfo,coin,&checkwacct,waddr->coinaddr)) != waddr || checkwacct != wacct ) { - errors[5]++; - flag |= (5 << 0); - if ( repairflag > 0 ) + //errors[5]++; + //flag |= (5 << 0); + //if ( repairflag > 0 ) { printf("waddrvalidate: need to manually setaccount to fix mismatch (%s:%s) <- (%s:%s)\n",checkwacct != 0 ? checkwacct->account : "",checkwaddr != 0 ? checkwaddr->coinaddr : "",wacct != 0 ? wacct->account : "",waddr->coinaddr); } @@ -586,14 +594,20 @@ uint8_t iguana_waddrvalidate(struct supernet_info *myinfo,struct iguana_info *co errors[0]++; flag |= (1 << 0); if ( repairflag > 0 ) + { + myinfo->dirty = (uint32_t)time(NULL); memset(&waddr->privkey,0,sizeof(waddr->privkey)); + } } if ( bitcoin_pubkeylen(waddr->pubkey) > 0 ) { errors[1]++; flag |= (1 << 1); if ( repairflag > 0 ) + { + myinfo->dirty = (uint32_t)time(NULL); memset(waddr->pubkey,0,sizeof(waddr->pubkey)); + } } } else checktype = coin->chain->pubtype; @@ -603,6 +617,7 @@ uint8_t iguana_waddrvalidate(struct supernet_info *myinfo,struct iguana_info *co flag |= (1 << 2); if ( repairflag > 0 ) { + myinfo->dirty = (uint32_t)time(NULL); waddr->addrtype = checktype; memcpy(waddr->rmd160,rmd160,sizeof(rmd160)); } @@ -617,7 +632,10 @@ uint8_t iguana_waddrvalidate(struct supernet_info *myinfo,struct iguana_info *co errors[3]++; flag |= (1 << 3); if ( repairflag > 0 ) + { + myinfo->dirty = (uint32_t)time(NULL); memcpy(waddr->pubkey,checkpub,sizeof(checkpub)); + } } } if ( (plen= bitcoin_pubkeylen(waddr->pubkey)) > 0 ) @@ -625,11 +643,23 @@ uint8_t iguana_waddrvalidate(struct supernet_info *myinfo,struct iguana_info *co calc_rmd160_sha256(rmd160,waddr->pubkey,plen); if ( memcmp(rmd160,waddr->rmd160,sizeof(rmd160)) != 0 ) { - errors[4]++; - flag |= (1 << 4); - if ( repairflag > 0 ) + for (i=0; i<20; i++) + if ( waddr->rmd160[i] != 0 ) + break; + if ( i != 20 ) + { + errors[4]++; + flag |= (1 << 4); + if ( repairflag > 0 ) + { + printf("waddrvalidate unrecoverable error: cant determine pubkey from rmd160\n"); + } + } + else { - printf("waddrvalidate unrecoverable error: cant determine pubkey from rmd160\n"); + memcpy(waddr->rmd160,rmd160,20); + bitcoin_address(waddr->coinaddr,coin->chain->pubtype,rmd160,sizeof(rmd160)); + myinfo->dirty = (uint32_t)time(NULL); } } } @@ -1130,7 +1160,7 @@ TWOSTRINGS_AND_INT(bitcoinrpc,importprivkey,wif,account,rescan) if ( retstr != 0 ) scrubfree(retstr); return(jprint(retjson,1)); - } + } else printf("null return from SuperNET_login\n"); } return(clonestr("{\"error\":\"cant calculate waddress\"}")); } diff --git a/iguana/main.c b/iguana/main.c index 6bbd9696f..546dc7872 100755 --- a/iguana/main.c +++ b/iguana/main.c @@ -1156,7 +1156,7 @@ void iguana_appletests(struct supernet_info *myinfo) if ( 1 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":64,\"newcoin\":\"BTCD\",\"active\":1,\"numhelpers\":4,\"poll\":100}"),0,myinfo->rpcport)) != 0 ) { free(str); - if ( 1 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":64,\"newcoin\":\"BTC\",\"active\":1,\"numhelpers\":4,\"poll\":100}"),0,myinfo->rpcport)) != 0 ) + if ( 0 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"RELAY\":1,\"VALIDATE\":1,\"prefetchlag\":-1,\"agent\":\"iguana\",\"method\":\"addcoin\",\"startpend\":4,\"endpend\":4,\"services\":129,\"maxpeers\":64,\"newcoin\":\"BTC\",\"active\":1,\"numhelpers\":4,\"poll\":100}"),0,myinfo->rpcport)) != 0 ) { free(str); if ( 0 && (str= SuperNET_JSON(myinfo,cJSON_Parse("{\"agent\":\"SuperNET\",\"method\":\"login\",\"handle\":\"alice\",\"password\":\"alice\",\"passphrase\":\"alice\"}"),0,myinfo->rpcport)) != 0 ) diff --git a/iguana/swaps/iguana_BTCswap.c b/iguana/swaps/iguana_BTCswap.c index c22671f09..fe119f68a 100755 --- a/iguana/swaps/iguana_BTCswap.c +++ b/iguana/swaps/iguana_BTCswap.c @@ -110,38 +110,24 @@ void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON 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; + int32_t n,num,completed; char *feetx = 0; struct iguana_info *coin; bits256 txid,signedtxid; cJSON *txobj;int64_t insurance,avail; uint8_t paymentscript[128]; struct bitcoin_statetx *ptr = 0; uint64_t *unspents; if ( (coin= iguana_coinfind("BTCD")) != 0 ) { insurance = IGUANA_BTCDMULT * instantdex_insurance(coin,instantdex_BTCsatoshis(A->offer.price64,A->offer.basevolume64)); - if ( (spend= iguana_spendset(myinfo,coin,insurance,coin->chain->txfee,0)) != 0 ) + txobj = bitcoin_txcreate(coin,0); + n = instantdex_outputinsurance(paymentscript,0,insurance,A->orderid); + bitcoin_txoutput(coin,txobj,paymentscript,n,insurance); + avail = iguana_availunspents(myinfo,&unspents,&num,coin,coin->chain->minconfirms,"*",coin->blockspace,sizeof(coin->blockspace)); + if ( (feetx= iguana_signunspents(myinfo,coin,&signedtxid,&completed,txobj,insurance,coin->changeaddr,coin->txfee,unspents,num)) != 0 ) { - txobj = bitcoin_txcreate(coin,0); - n = instantdex_outputinsurance(paymentscript,0,insurance,A->orderid); - bitcoin_txoutput(coin,txobj,paymentscript,n,insurance); - iguana_addinputs(coin,spend,txobj,0xffffffff); - if ( spend->change > coin->chain->txfee ) - { - len = bitcoin_standardspend(paymentscript,0,spend->change160); - bitcoin_txoutput(coin,txobj,paymentscript,len,spend->change); - } - txobj = iguana_signtx(myinfo,coin,&txid,&feetx,spend,txobj,0); - if ( feetx != 0 ) - { - ptr = calloc(1,sizeof(*ptr) + strlen(feetx) + 1); - strcpy(ptr->txbytes,feetx); - ptr->txid = txid; - //printf("%s feetx.%s\n",A->offer.myside != 0 ? "BOB" : "ALICE",feetx); - //disp_tx(myinfo,coin,"feetx",feetx); - free(feetx); - } - else printf("error signing %s feetx numinputs.%d\n",A->offer.myside != 0 ? "BOB" : "ALICE",spend->numinputs); - free(spend); - } - else - { - printf("no unspents to spend\n"); + ptr = calloc(1,sizeof(*ptr) + strlen(feetx) + 1); + strcpy(ptr->txbytes,feetx); + ptr->txid = txid; + //printf("%s feetx.%s\n",A->offer.myside != 0 ? "BOB" : "ALICE",feetx); + //disp_tx(myinfo,coin,"feetx",feetx); + free(feetx); } + else printf("error creating %s feetx\n",A->offer.myside != 0 ? "BOB" : "ALICE"); } return(ptr); } @@ -199,30 +185,25 @@ int32_t instantdex_feetxverify(struct supernet_info *myinfo,struct iguana_info * struct bitcoin_statetx *instantdex_bobtx(struct supernet_info *myinfo,struct iguana_info *coin,bits256 pub1,bits256 pub2,bits256 priv,uint32_t reftime,int64_t amount,int32_t depositflag) { cJSON *txobj; int32_t n,secretstart; char *signedtx = 0; struct bitcoin_statetx *ptr = 0; - uint8_t script[1024],secret[20]; bits256 txid; struct bitcoin_spend *spend; uint32_t locktime; int64_t insurance; + uint8_t script[1024],secret[20]; bits256 txid,signedtxid; uint32_t locktime; int64_t avail,insurance; int32_t completed,num; uint64_t *unspents; if ( coin == 0 ) return(0); locktime = (uint32_t)(reftime + INSTANTDEX_LOCKTIME * (1 + depositflag)); txobj = bitcoin_txcreate(coin,locktime); insurance = instantdex_insurance(coin,amount); - if ( (spend= iguana_spendset(myinfo,coin,amount + insurance,coin->chain->txfee,0)) != 0 ) + calc_rmd160_sha256(secret,priv.bytes,sizeof(priv)); + n = instantdex_bobscript(script,0,&secretstart,locktime,pub1,secret,pub2); + bitcoin_txoutput(coin,txobj,script,n,amount + depositflag*insurance*100); + avail = iguana_availunspents(myinfo,&unspents,&num,coin,coin->chain->minconfirms,"*",coin->blockspace,sizeof(coin->blockspace)); + if ( (signedtx= iguana_signunspents(myinfo,coin,&signedtxid,&completed,txobj,amount + insurance,coin->changeaddr,coin->txfee,unspents,num)) != 0 ) { - calc_rmd160_sha256(secret,priv.bytes,sizeof(priv)); - n = instantdex_bobscript(script,0,&secretstart,locktime,pub1,secret,pub2); - bitcoin_txoutput(coin,txobj,script,n,amount + depositflag*insurance*100); - iguana_addinputs(coin,spend,txobj,0xffffffff); - txobj = iguana_signtx(myinfo,coin,&txid,&signedtx,spend,txobj,0); - if ( signedtx != 0 ) - { - ptr = calloc(1,sizeof(*ptr) + strlen(signedtx) + 1); - strcpy(ptr->txbytes,signedtx); - ptr->txid = txid; - //printf("bob deposit.%s\n",signedtx); - //disp_tx(myinfo,coin,depositflag != 0 ? "deposit" : "payment",signedtx); - free(signedtx); - } else printf("error signing bobdeposit numinputs.%d\n",spend->numinputs); - free(spend); - } + ptr = calloc(1,sizeof(*ptr) + strlen(signedtx) + 1); + strcpy(ptr->txbytes,signedtx); + ptr->txid = txid; + //printf("bob deposit.%s\n",signedtx); + //disp_tx(myinfo,coin,depositflag != 0 ? "deposit" : "payment",signedtx); + free(signedtx); + } else printf("error signing bobdeposit\n"); free_json(txobj); return(ptr); } @@ -304,15 +285,14 @@ int32_t instantdex_altpaymentverify(struct supernet_info *myinfo,struct iguana_i struct bitcoin_statetx *instantdex_alicetx(struct supernet_info *myinfo,struct iguana_info *altcoin,char *msigaddr,bits256 pubAm,bits256 pubBn,int64_t amount) { - cJSON *txobj; int32_t n; char *signedtx = 0; uint8_t script[1024]; struct bitcoin_spend *spend; struct bitcoin_statetx *ptr = 0; bits256 txid; - if ( altcoin != 0 && (spend= iguana_spendset(myinfo,altcoin,amount,altcoin->chain->txfee,0)) != 0 ) + cJSON *txobj; int32_t n,completed,num; char *signedtx = 0; uint8_t script[1024]; struct bitcoin_statetx *ptr = 0; bits256 txid,signedtxid; uint64_t *unspents; int64_t avail; + if ( altcoin != 0 ) { txobj = bitcoin_txcreate(altcoin,0); n = instantdex_alicescript(script,0,msigaddr,altcoin->chain->p2shtype,pubAm,pubBn); bitcoin_txoutput(altcoin,txobj,script,n,amount); - iguana_addinputs(altcoin,spend,txobj,0xffffffff); - txobj = iguana_signtx(myinfo,altcoin,&txid,&signedtx,spend,txobj,0); - if ( signedtx != 0 ) + avail = iguana_availunspents(myinfo,&unspents,&num,altcoin,altcoin->chain->minconfirms,"*",altcoin->blockspace,sizeof(altcoin->blockspace)); + if ( (signedtx= iguana_signunspents(myinfo,altcoin,&signedtxid,&completed,txobj,amount,altcoin->changeaddr,altcoin->txfee,unspents,num)) != 0 ) { printf("alice payment.%s\n",signedtx); //disp_tx(myinfo,altcoin,"altpayment",signedtx); @@ -320,9 +300,7 @@ struct bitcoin_statetx *instantdex_alicetx(struct supernet_info *myinfo,struct i ptr->txid = txid; strcpy(ptr->txbytes,signedtx); free(signedtx); - } - else printf("error signing alicetx numinputs.%d\n",spend->numinputs); - free(spend); + } else printf("error signing alicetx\n"); free_json(txobj); } return(ptr); diff --git a/iguana/tests/decoderawtransaction b/iguana/tests/decoderawtransaction index a085237ba..fbccbbd4c 100755 --- a/iguana/tests/decoderawtransaction +++ b/iguana/tests/decoderawtransaction @@ -1 +1 @@ -curl --url "http://127.0.0.1:7778" --data "{\"method\":\"decoderawtransaction\",\"params\":[\"0100000030e82f570100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0210270000000000001976a91410acba3a841fae68aba4b5ff162714c493bcc04e88ac44c71d00000000001976a9141af1412c5e9f9ec862c91d55318330df1a02c64388ac00000000\"]}" +curl --url "http://127.0.0.1:7778" --data "{\"method\":\"decoderawtransaction\",\"params\":[\"0100000093b7325701f6d17d847b7096cdd9b79e4df4b74aabb9ac34b7abd4f9fce19d761e97cca0e80000000000ffffffff0240420f00000000001976a91410acba3a841fae68aba4b5ff162714c493bcc04e88acd0300e00000000001976a914d8b8c039206af6cec82bca950f592801e62808cb88ac00000000\"]}" diff --git a/iguana/tests/signrawtransaction b/iguana/tests/signrawtransaction index 6063819fa..1cc56768c 100755 --- a/iguana/tests/signrawtransaction +++ b/iguana/tests/signrawtransaction @@ -1,2 +1,2 @@ -curl --url "http://127.0.0.1:7778" --data "{\"method\":\"signrawtransaction\",\"params\":[\"0100000086cc2c5701f6d17d847b7096cdd9b79e4df4b74aabb9ac34b7abd4f9fce19d761e97cca0e80000000000ffffffff0240420f00000000001976a91410acba3a841fae68aba4b5ff162714c493bcc04e88acd0300e00000000001976a914d8b8c039206af6cec82bca950f592801e62808cb88ac00000000\", [{\"txid\":\"e8a0cc971e769de1fcf9d4abb734acb9ab4ab7f44d9eb7d9cd96707b847dd1f6\",\"vout\":0,\"scriptPubKey\":\"2102d14a195654f536df6dfe5a38278d1b470d00f17de78eeb5ce9e9eea9edb2c212ac\"}], [\"UqvuZXEAVXDXJkL4j4Xq6qoMdeJfPF1aNsCzmzfZaQ1ZgBTwfmWn\"], \"ALL\"] }" +curl --url "http://127.0.0.1:7778" --data "{\"method\":\"signrawtransaction\",\"params\":[\"0100000093b7325701f6d17d847b7096cdd9b79e4df4b74aabb9ac34b7abd4f9fce19d761e97cca0e80000000000ffffffff0240420f00000000001976a91410acba3a841fae68aba4b5ff162714c493bcc04e88acd0300e00000000001976a914d8b8c039206af6cec82bca950f592801e62808cb88ac00000000\", [{\"txid\":\"e8a0cc971e769de1fcf9d4abb734acb9ab4ab7f44d9eb7d9cd96707b847dd1f6\",\"vout\":0,\"scriptPubKey\":\"2102d14a195654f536df6dfe5a38278d1b470d00f17de78eeb5ce9e9eea9edb2c212ac\"}], [\"UqvuZXEAVXDXJkL4j4Xq6qoMdeJfPF1aNsCzmzfZaQ1ZgBTwfmWn\"], \"ALL\"] }"