Browse Source

sendtoaddress fixed

reworked internals for basilisk/history api by using iguana/balance api
and sendtoaddress uses this data. tested finding and using utxo in
completed bundles, and also in the RT bundle. Left to test are
detecting a spend of RT bundle in the RT bundle. also amounts and
txfees are a bit off, but basic sendtoaddress should work in all cases
other than bugs

left to do is to lock utxo after being used so multiple tx per block
can be sent, otherwise the same utxo could be selected and that is
invalid
release/v0.1
jl777 8 years ago
parent
commit
421314f16d
  1. 14
      basilisk/basilisk.c
  2. 58
      basilisk/basilisk_bitcoin.c
  3. 5
      iguana/iguana_payments.c
  4. 11
      iguana/iguana_sign.c
  5. 12
      iguana/iguana_unspents.c
  6. 23
      iguana/iguana_wallet.c
  7. 1
      iguana/tests/balance2
  8. 2
      iguana/tests/history
  9. 1
      includes/iguana_funcs.h

14
basilisk/basilisk.c

@ -935,11 +935,15 @@ HASH_ARRAY_STRING(basilisk,history,hash,vals,hexstr)
return(clonestr("{\"error\":\"couldnt find coin\"}"));
unspents = cJSON_CreateArray();
spends = cJSON_CreateArray();
portable_mutex_lock(&myinfo->bu_mutex);
HASH_ITER(hh,myinfo->wallet,wacct,tmp)
{
HASH_ITER(hh,wacct->waddr,waddr,tmp2)
{
if ( waddr->Cunspents != 0 && (array= jobj(waddr->Cunspents,coin->symbol)) != 0 )
if ( waddr->Cunspents != 0 )
{
//printf("Cunspents.(%s)\n",jprint(waddr->Cunspents,0));
if ( (array= jobj(waddr->Cunspents,coin->symbol)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) > 0 )
{
@ -948,10 +952,16 @@ HASH_ARRAY_STRING(basilisk,history,hash,vals,hexstr)
}
jaddi(unspents,jduplicate(array));
}
if ( waddr->Cspends != 0 && (array= jobj(waddr->Cspends,coin->symbol)) != 0 )
}
if ( waddr->Cspends != 0 )
{
//printf("Cspends.(%s)\n",jprint(waddr->Cspends,0));
if ( (array= jobj(waddr->Cspends,coin->symbol)) != 0 )
jaddi(spends,jduplicate(array));
}
}
}
portable_mutex_unlock(&myinfo->bu_mutex);
retjson = cJSON_CreateObject();
jaddstr(retjson,"result","success");
jadd(retjson,"unspents",unspents);

58
basilisk/basilisk_bitcoin.c

@ -299,7 +299,7 @@ int32_t basilisk_bitcoinavail(struct iguana_info *coin)
void *basilisk_bitcoinbalances(struct basilisk_item *Lptr,struct supernet_info *myinfo,struct iguana_info *coin,char *remoteaddr,uint32_t basilisktag,int32_t timeoutmillis,cJSON *vals)
{
int64_t balance,total = 0; int32_t i,n,hist; char *str; cJSON *spends,*unspents,*retjson,*item,*addresses,*array = cJSON_CreateArray();
int64_t balance,total = 0; int32_t i,j,n,hist; char *str; cJSON *spends,*unspents,*retjson,*item,*addresses,*array = cJSON_CreateArray();
spends = unspents = 0;
if ( (hist= juint(vals,"history")) != 0 )
{
@ -315,10 +315,15 @@ void *basilisk_bitcoinbalances(struct basilisk_item *Lptr,struct supernet_info *
{
if ( (str= jstri(addresses,i)) != 0 )
{
for (j=0; j<n; j++)
if ( jstri(addresses,j) != 0 && strcmp(jstri(addresses,j),str) == 0 )
break;
if ( j == n )
continue;
balance = iguana_addressreceived(myinfo,coin,vals,remoteaddr,0,0,unspents,spends,str,juint(vals,"minconf"),juint(vals,"firstheight"));
item = cJSON_CreateObject();
jaddnum(item,jstri(addresses,i),dstr(balance));
jaddstr(item,"address",jstri(addresses,i));
jaddnum(item,str,dstr(balance));
jaddstr(item,"address",str);
jaddi(array,item);
total += balance;
}
@ -337,6 +342,7 @@ void *basilisk_bitcoinbalances(struct basilisk_item *Lptr,struct supernet_info *
jaddnum(retjson,"RTheight",coin->RTheight);
jaddnum(retjson,"longest",coin->longestchain);
jaddnum(retjson,"lag",coin->longestchain- coin->RTheight);
//printf("RETSTR.(%s)\n",jprint(retjson,0));
Lptr->retstr = jprint(retjson,1);
return(Lptr);
}
@ -526,7 +532,10 @@ char *basilisk_bitcoinrawtx(struct supernet_info *myinfo,struct iguana_info *coi
decode_hex(&buf[sizeof(buf) - oplen],oplen,opreturn);
spendlen = datachain_datascript(coin,buf,&buf[sizeof(buf) - oplen],oplen);
if ( (burnamount= SATOSHIDEN * jdouble(valsobj,"burn")) < 10000 )
burnamount = 10000;
{
//burnamount = 10000;
printf("low burnamount %.8f\n",dstr(burnamount));
}
bitcoin_txoutput(txobj,buf,spendlen,burnamount);
oplen = 0;
} else oplen = datachain_opreturnscript(coin,buf,opreturn,oplen);
@ -823,8 +832,8 @@ HASH_ARRAY_STRING(basilisk,rawtx,hash,vals,hexstr)
jaddnum(vals,"fanout",(int32_t)sqrt(NUMRELAYS));
if ( coin != 0 )
{
if ( juint(vals,"burn") == 0 )
jaddnum(vals,"burn",0.0001);
//if ( juint(vals,"burn") == 0 )
// jaddnum(vals,"burn",0.0001);
if ( (basilisktag= juint(vals,"basilisktag")) == 0 )
basilisktag = rand();
if ( (timeoutmillis= juint(vals,"timeout")) <= 0 )
@ -883,6 +892,29 @@ int32_t basilisk_unspentfind(struct supernet_info *myinfo,struct iguana_info *co
return(-1);
}
void basilisk_jsonmerge(cJSON *json,char *symbol,cJSON *array)
{
int32_t i,j,n,m; cJSON *jobj,*iobj,*dest;
if ( (dest= jarray(&m,json,symbol)) == 0 )
dest = cJSON_CreateArray();
if ( dest != 0 && (n= cJSON_GetArraySize(array)) > 0 )
{
m = cJSON_GetArraySize(dest);
for (i=0; i<n; i++)
{
iobj = jitem(array,i);
for (j=0; j<m; j++)
{
jobj = jitem(dest,j);
if ( bits256_cmp(jbits256(jobj,"txid"),jbits256(iobj,"txid")) == 0 && jint(jobj,"vout") == jint(iobj,"vout") )
break;
}
if ( j == m )
jaddi(dest,jduplicate(iobj));
}
}
}
void basilisk_unspent_update(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *json)
{
cJSON *unspents,*spends,*item; int32_t n; char *address; struct iguana_waccount *wacct; struct iguana_waddress *waddr=0;
@ -892,11 +924,12 @@ void basilisk_unspent_update(struct supernet_info *myinfo,struct iguana_info *co
if ( (address= jstr(item,"address")) != 0 && (waddr= iguana_waddresssearch(myinfo,&wacct,address)) != 0 )
{
if ( waddr->Cspends == 0 )
{
waddr->Cspends = cJSON_CreateObject();
if ( jobj(waddr->Cspends,coin->symbol) != 0 )
jdelete(waddr->Cspends,coin->symbol); // better merge and error check if basilisk
jadd(waddr->Cspends,coin->symbol,jduplicate(spends));
} else basilisk_jsonmerge(waddr->Cspends,coin->symbol,spends);
}
//printf("merge spends.(%s)\n",jprint(spends,0));
}
if ( (unspents= jarray(&n,json,"unspents")) != 0 )
{
@ -904,11 +937,12 @@ void basilisk_unspent_update(struct supernet_info *myinfo,struct iguana_info *co
if ( (address= jstr(item,"address")) != 0 && (waddr= iguana_waddresssearch(myinfo,&wacct,address)) != 0 )
{
if ( waddr->Cunspents == 0 )
{
waddr->Cunspents = cJSON_CreateObject();
if ( jobj(waddr->Cunspents,coin->symbol) != 0 )
jdelete(waddr->Cunspents,coin->symbol); // better merge and error check if basilisk
jadd(waddr->Cunspents,coin->symbol,jduplicate(unspents));
} else basilisk_jsonmerge(waddr->Cunspents,coin->symbol,unspents);
}
//printf("merge unspents.(%s)\n",jprint(unspents,0));
}
}
@ -924,14 +958,18 @@ void basilisk_unspents_update(struct supernet_info *myinfo,struct iguana_info *c
jaddstr(vals,"coin",coin->symbol);
if ( (retstr= basilisk_balances(myinfo,coin,0,0,GENESIS_PUBKEY,vals,"")) != 0 )
{
//printf("basilisk_balances.(%s)\n",retstr);
if ( (retarray= cJSON_Parse(retstr)) != 0 )
{
portable_mutex_lock(&myinfo->bu_mutex);
iguana_wallet_Cclear(myinfo,coin->symbol);
if ( is_cJSON_Array(retarray) != 0 )
{
for (i=0; i<cJSON_GetArraySize(retarray); i++)
basilisk_unspent_update(myinfo,coin,jitem(retarray,i));
} else basilisk_unspent_update(myinfo,coin,retarray);
free_json(retarray);
portable_mutex_unlock(&myinfo->bu_mutex);
}
free(retstr);
}

5
iguana/iguana_payments.c

@ -218,7 +218,7 @@ cJSON *iguana_inputjson(bits256 txid,int32_t vout,uint8_t *spendscript,int32_t s
cJSON *iguana_RTinputsjson(struct supernet_info *myinfo,struct iguana_info *coin,uint64_t *totalp,uint64_t amount,struct iguana_outpoint *unspents,int32_t num)
{
cJSON *vins; uint8_t spendscript[IGUANA_MAXSCRIPTSIZE]; struct iguana_txid *T; struct iguana_unspent *U,*u; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; char coinaddr[64]; int32_t vout,height,abovei,belowi,i,spendlen,ind; uint32_t txidind; struct iguana_ramchaindata *rdata; bits256 txid; int64_t above,below,total = 0,remains = amount; struct iguana_outpoint outpt; uint64_t RTspent;
cJSON *vins; uint8_t spendscript[IGUANA_MAXSCRIPTSIZE]; struct iguana_txid *T; struct iguana_unspent *U,*u; struct iguana_bundle *bp; struct iguana_ramchain *ramchain; char coinaddr[64]; int32_t vout,height,abovei,belowi,i,spendlen,ind; uint32_t txidind; struct iguana_ramchaindata *rdata; bits256 txid; int64_t above,below,total = 0,remains = amount; struct iguana_outpoint outpt,outpt2; //uint64_t RTspent;
*totalp = 0;
vins = cJSON_CreateArray();
for (i=0; i<num; i++)
@ -274,7 +274,7 @@ cJSON *iguana_RTinputsjson(struct supernet_info *myinfo,struct iguana_info *coin
u = &U[outpt.unspentind];
if ( (txidind= u->txidind) > 0 && txidind < rdata->numtxids )
{
if ( iguana_unspentindfind(myinfo,coin,&RTspent,coinaddr,spendscript,&spendlen,&amount,&height,T[txidind].txid,u->vout,coin->bundlescount-1,0) == outpt.unspentind && spendlen > 0 )
if ( iguana_RTunspentindfind(myinfo,coin,&outpt2,coinaddr,spendscript,&spendlen,&amount,&height,T[txidind].txid,u->vout,coin->bundlescount-1,0) == 0 && spendlen > 0 )
{
jaddi(vins,iguana_inputjson(T[txidind].txid,u->vout,spendscript,spendlen));
total += outpt.value;
@ -374,6 +374,7 @@ char *iguana_calcrawtx(struct supernet_info *myinfo,struct iguana_info *coin,cJS
free(unspents);
return(0);
}
printf("avail %.8f satoshis %.8f, txfee %.8f burnamount %.8f\n",dstr(avail),dstr(satoshis),dstr(txfee),dstr(burnamount));
if ( txobj != 0 && avail >= satoshis+txfee )
{
if ( (vins= iguana_RTinputsjson(myinfo,coin,&total,satoshis + txfee,unspents,num)) != 0 )

11
iguana/iguana_sign.c

@ -154,7 +154,10 @@ int32_t iguana_parsehexstr(uint8_t **destp,uint16_t *lenp,uint8_t *dest2,int32_t
n = (int32_t)strlen(hexstr) >> 1;
//printf("addhex.(%s) %d\n",hexstr,n);
if ( serialized == 0 )
serialized = *destp;
{
if ( (serialized= *destp) == 0 )
printf("iguana_parsehexstr null serialized and destp\n");
}
if ( serialized != 0 )
{
decode_hex(serialized,n,hexstr);
@ -323,7 +326,9 @@ int32_t iguana_parsevinobj(struct supernet_info *myinfo,struct iguana_info *coin
len += iguana_rwnum(rwflag,&serialized[len],sizeof(vin->sequence),&vin->sequence);
if ( spendstr != 0 )
{
n = iguana_parsehexstr(&vin->spendscript,&vin->spendlen,V!=0?V->spendscript:0,V!=0?&V->spendlen:0,0,spendstr);
//printf("serialized.%p len.%d\n",serialized,len);
n = iguana_parsehexstr(&vin->spendscript,&vin->spendlen,V!=0?V->spendscript:0,V!=0?&V->spendlen:0,&serialized[len],spendstr);
len += n;
}
return(len);
}
@ -603,6 +608,7 @@ bits256 iguana_parsetxobj(struct supernet_info *myinfo,struct iguana_info *coin,
return(txid);
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);
if ( msg->tx_in > 0 && msg->tx_in*sizeof(struct iguana_msgvin) < maxsize )
{
for (i=0; i<msg->tx_in; i++)
@ -620,6 +626,7 @@ bits256 iguana_parsetxobj(struct supernet_info *myinfo,struct iguana_info *coin,
return(txid);
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);
if ( msg->tx_out > 0 && msg->tx_out*sizeof(struct iguana_msgvout) < maxsize )
{
for (i=0; i<msg->tx_out; i++)

12
iguana/iguana_unspents.c

@ -435,6 +435,7 @@ int32_t iguana_RTscanunspents(struct supernet_info *myinfo,struct iguana_info *c
else printf("unspent has no parent?\n");
outpt.isptr = 1;
outpt.ptr = unspent;
outpt.value = unspent->value;
outpt.hdrsi = unspent->height / coin->chain->bundlesize;
if ( array != 0 )
jaddi(array,iguana_RTunspentjson(myinfo,coin,outpt,txid,unspent->vout,unspent->value,0,rmd160,coinaddr,pubkey33,spentheight,remoteaddr));
@ -555,7 +556,7 @@ int32_t iguana_RTpkhasharray(struct supernet_info *myinfo,struct iguana_info *co
if ( max > coin->bundlescount )
max = coin->bundlescount;
//printf("minconf.%d maxconf.%d max.%d addr.%s last.%d maxunspents.%d\n",minconf,maxconf,max,coinaddr,lastheight,maxunspents);
for (total=n=i=0; i<max+(lastheight>=coin->RTheight); i++)
for (total=n=i=0; i<max+(lastheight>=coin->firstRTheight); i++)
{
if ( i != max && (bp= coin->bundles[i]) == 0 )
continue;
@ -635,7 +636,7 @@ int64_t iguana_RTunspents(struct supernet_info *myinfo,struct iguana_info *coin,
continue;
bitcoin_address(coinaddr,addrtypes[i],&rmdarray[i * 20],20);
*numunspentsp = 0;
iguana_RTpkhasharray(myinfo,coin,array,minconf,maxconf,&total,P,coin->bundlescount,&rmdarray[i * 20],coinaddr,&pubkeys[33*i],lastheight,&unspents[numunspents],numunspentsp,maxunspents,remoteaddr,includespent);
iguana_RTpkhasharray(myinfo,coin,array,minconf,maxconf,&total,P,coin->bundlescount,&rmdarray[i * 20],coinaddr,&pubkeys[33*i],lastheight,unspents != 0 ? &unspents[numunspents] : 0,numunspentsp,maxunspents,remoteaddr,includespent);
//printf("iguana_unspents: i.%d of %d: %s %.8f numunspents.%d\n",i,numrmds,coinaddr,dstr(total),*numunspentsp);
maxunspents -= *numunspentsp;
numunspents += *numunspentsp;
@ -789,7 +790,7 @@ int32_t iguana_RTunspent_check(struct supernet_info *myinfo,struct iguana_info *
{
bits256 txid; int32_t vout,spentheight;
memset(&txid,0,sizeof(txid));
printf("RTunspent_check needs to be ported\n");
printf("RTunspent_check needs to be ported to prevent reusing utxo, but should work if one spend per block\n");
return(0);
if ( iguana_RTunspentind2txid(myinfo,coin,&spentheight,&txid,&vout,outpt) == 0 )
{
@ -846,10 +847,11 @@ int32_t iguana_RTunspentslists(struct supernet_info *myinfo,struct iguana_info *
continue;
if ( coin->FULLNODE != 0 || coin->VALIDATENODE != 0 )
{
numunspents += iguana_RTaddr_unspents(myinfo,coin,&sum,&unspents[numunspents],max-numunspents,coinaddr,remoteaddr,coin->blocks.hwmchain.height - minconf,0);
numunspents += iguana_RTaddr_unspents(myinfo,coin,&sum,&unspents[numunspents],max-numunspents,coinaddr,remoteaddr,1<<30,0);
}
else
{
portable_mutex_lock(&myinfo->bu_mutex);
if ( (waddr= iguana_waddresssearch(myinfo,&wacct,coinaddr)) != 0 )
{
if ( waddr->Cunspents != 0 && (array= jobj(waddr->Cunspents,coin->symbol)) != 0 )
@ -868,6 +870,7 @@ int32_t iguana_RTunspentslists(struct supernet_info *myinfo,struct iguana_info *
}
}
}
portable_mutex_unlock(&myinfo->bu_mutex);
}
if ( numunspents > max || sum > required )
break;
@ -875,6 +878,7 @@ int32_t iguana_RTunspentslists(struct supernet_info *myinfo,struct iguana_info *
}
}
*totalp = sum;
printf("numunspents.%d sum %.8f\n",numunspents,dstr(sum));
return(numunspents);
}

23
iguana/iguana_wallet.c

@ -330,6 +330,21 @@ cJSON *iguana_getaddressesbyaccount(struct supernet_info *myinfo,struct iguana_i
return(array);
}
void iguana_wallet_Cclear(struct supernet_info *myinfo,char *symbol)
{
struct iguana_waccount *subset,*tmp; struct iguana_waddress *waddr,*tmp2;
HASH_ITER(hh,myinfo->wallet,subset,tmp)
{
HASH_ITER(hh,subset->waddr,waddr,tmp2)
{
if ( waddr->Cspends != 0 )
free_json(waddr->Cspends), waddr->Cspends = 0;
if ( waddr->Cunspents != 0 )
free_json(waddr->Cunspents), waddr->Cunspents = 0;
}
}
}
struct iguana_waddress *iguana_ismine(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,uint8_t addrtype,uint8_t pubkey[65],uint8_t rmd160[20])
{
struct iguana_waccount *wacct; struct iguana_waddress *waddr = 0;
@ -986,9 +1001,9 @@ int64_t iguana_addressreceived(struct supernet_info *myinfo,struct iguana_info *
jaddibits256(txids,jbits256(item,"txid"));
if ( vouts != 0 )
jaddinum(vouts,jint(item,"vout"));
if ( unspents != 0 && jobj(item,"unspent") != 0 )
if ( unspents != 0 && (jobj(item,"spent") == 0 || jobj(item,"dest") == 0) )
jaddi(unspents,jduplicate(item));
if ( spends != 0 && jobj(item,"spent") != 0 )
if ( spends != 0 && jobj(item,"spent") != 0 && jobj(item,"dest") != 0 )
jaddi(spends,jduplicate(item));
}
}
@ -997,6 +1012,10 @@ int64_t iguana_addressreceived(struct supernet_info *myinfo,struct iguana_info *
}
free(balancestr);
}
//if ( spends != 0 )
// printf("SPENDS.(%s)\n",jprint(spends,0));
//if ( unspents != 0 )
// printf("UNSPENTS.(%s)\n",jprint(unspents,0));
return(balance);
}

1
iguana/tests/balance2

@ -0,0 +1 @@
curl --url "http://127.0.0.1:7778" --data "{\"activecoin\":\"BTCD\",\"timeout\":20000,\"agent\":\"iguana\",\"method\":\"balance\",\"address\":\"RFMEYcxuBL8S7UPdUbzXunPtS4p82HRcKs\"}"

2
iguana/tests/history

@ -1 +1 @@
curl --url "http://127.0.0.1:7778" --data "{\"timeout\":20000,\"agent\":\"basilisk\",\"method\":\"history\",\"vals\":{\"coin\":\"BTC\"}}"
curl --url "http://127.0.0.1:7778" --data "{\"timeout\":20000,\"agent\":\"basilisk\",\"method\":\"history\",\"vals\":{\"coin\":\"BTCD\"}}"

1
includes/iguana_funcs.h

@ -426,6 +426,7 @@ struct iguana_waddress *iguana_waddresssearch(struct supernet_info *myinfo,struc
cJSON *iguana_RTlistunspent(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *argarray,int32_t minconf,int32_t maxconf,char *remoteaddr,int32_t includespends);
void calc_shares(struct supernet_info *myinfo,uint8_t *shares,uint8_t *secret,int32_t size,int32_t width,int32_t M,int32_t N,uint8_t *sharenrs,uint8_t *space,int32_t spacesize);
//struct basilisk_spend *basilisk_addspend(struct supernet_info *myinfo,char *symbol,bits256 txid,uint16_t vout,int32_t addflag);
void iguana_wallet_Cclear(struct supernet_info *myinfo,char *symbol);
int64_t _RTgettxout(struct iguana_info *coin,struct iguana_RTtxid **ptrp,int32_t *heightp,int32_t *scriptlenp,uint8_t *script,uint8_t *rmd160,char *coinaddr,bits256 txid,int32_t vout,int32_t mempool);
int32_t _iguana_RTunspentfind(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,int32_t *voutp,uint8_t *spendscript,struct iguana_outpoint outpt,int64_t value);
int32_t basilisk_unspentfind(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,int32_t *voutp,uint8_t *spendscript,struct iguana_outpoint outpt,int64_t value);

Loading…
Cancel
Save