Browse Source

wallet fixes, must update

release/v0.1
jl777 9 years ago
parent
commit
2e5423e2d3
  1. 3
      iguana/iguana777.h
  2. 4
      iguana/iguana_interpreter.c
  3. 175
      iguana/iguana_payments.c
  4. 18
      iguana/iguana_sign.c
  5. 12
      iguana/iguana_unspents.c
  6. 2
      iguana/iguana_volatiles.c
  7. 68
      iguana/iguana_wallet.c
  8. 2
      iguana/main.c
  9. 84
      iguana/swaps/iguana_BTCswap.c
  10. 2
      iguana/tests/decoderawtransaction
  11. 2
      iguana/tests/signrawtransaction

3
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;

4
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<siglen; i++)
/*int32_t i; for (i=0; i<siglen; i++)
printf("%02x",sig[i]);
printf(" sig, ");
for (i=0; i<plen; i++)
printf("%02x",pubkey[i]);
char str[65]; printf(" checksig sigtxid.%s\n",bits256_str(str,sigtxid));
char str[65]; printf(" checksig sigtxid.%s\n",bits256_str(str,sigtxid));*/
if ( bitcoin_pubkeylen(pubkey) == plen && plen > 0 && siglen > 0 && siglen < 74 )
return(bitcoin_verify(coin->ctx,sig,siglen-1,sigtxid,pubkey,plen) == 0);
return(0);

175
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<num; i++)
{
for (i=0; i<num; i++)
{
value = unspents[(i << 1) + 1];
if ( value == -1 )
iguana_utxofind(coin,(int32_t)(unspents[i << 1] >> 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 <bitcoinaddress> <amount> [comment] [comment-to] <amount> is a real and is rounded to 8 decimal places. Returns the transaction ID <txid> 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; i<numwaddrs; i++)
{
unspents = (uint64_t *)((long)coin->blockspace + sizeof(*waddrs)*numwaddrs);
for (i=num=0; i<numwaddrs; i++)
if ( (waddr= waddrs[i]) != 0 && waddr->numunspents > 0 )
{
if ( (waddr= waddrs[i]) != 0 && waddr->numunspents > 0 )
for (j=0; j<waddr->numunspents; j++)
{
for (j=0; j<waddr->numunspents; 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 <bitcoinaddress> <amount> [comment] [comment-to] <amount> is a real and is rounded to 8 decimal places. Returns the transaction ID <txid> 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 )

18
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

12
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 )

2
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 )

68
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\"}"));
}

2
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 )

84
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);

2
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\"]}"

2
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\"] }"

Loading…
Cancel
Save