/******************************************************************************
* Copyright © 2014 - 2017 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 . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// compare multiple rawtx returns
# 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 ; i < seconds ; i + + )
{
if ( i = = 0 )
iguana_send ( coin , 0 , serialized , len ) ;
if ( coin - > APIblockstr ! = 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 , & 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 , & 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 ( myinfo - > ctx , 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 ; i < V . N ; i + + )
{
if ( V . signers [ i ] . coinaddr [ 0 ] ! = 0 & & ( waddr = iguana_waddresssearch ( myinfo , & wacct , V . signers [ i ] . coinaddr ) ) ! = 0 & & waddr - > wifstr [ 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 = cJSON_CreateObject ( ) ;
if ( ( asmtype = iguana_calcrmd160 ( coin , asmstr , & V , script , scriptlen , rand256 ( 0 ) , 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 < V . N ; i + + )
jaddistr ( addrobj , V . signers [ i ] . coinaddr ) ;
jadd ( scriptobj , " addresses " , addrobj ) ;
if ( scriptlen ! = 0 )
{
bitcoin_address ( coinaddr , coin - > chain - > p2shtype , script , scriptlen ) ;
jaddstr ( scriptobj , " p2sh " , coinaddr ) ;
}
memcpy ( rmd160 , V . rmd160 , 20 ) ;
}
return ( scriptobj ) ;
}
int32_t iguana_RTbestunspent ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t * aboveip , int64_t * abovep , int32_t * belowip , int64_t * belowp , struct iguana_outpoint * unspents , int32_t numunspents , uint64_t value , int32_t maxmode )
{
int32_t i , abovei , belowi ; int64_t above , below , gap , atx_value , maxvalue = 0 ;
abovei = belowi = - 1 ;
for ( above = below = i = 0 ; i < numunspents ; i + + )
{
if ( ( atx_value = unspents [ i ] . value ) < = 0 )
{
//printf("illegal value.%d\n",i);
continue ;
}
if ( iguana_RTunspent_check ( myinfo , coin , unspents [ i ] ) ! = 0 )
{
printf ( " (%d u%d) %.8f already used \n " , unspents [ i ] . hdrsi , unspents [ i ] . unspentind , dstr ( atx_value ) ) ;
continue ;
}
if ( maxmode = = 0 )
{
//printf("(%.8f vs %.8f)\n",dstr(atx_value),dstr(value));
if ( atx_value = = value )
{
* aboveip = * belowip = i ;
* abovep = * belowp = 0 ;
return ( i ) ;
}
else if ( atx_value > value )
{
gap = ( atx_value - value ) ;
if ( above = = 0 | | gap < above )
{
above = gap ;
abovei = i ;
}
} else gap = ( value - atx_value ) ;
if ( below = = 0 | | gap < below )
{
below = gap ;
belowi = i ;
}
}
else
{
//printf("(%.8f vs %.8f)\n",dstr(atx_value),dstr(maxvalue));
if ( atx_value > maxvalue )
{
maxvalue = atx_value ;
above = ( atx_value - value ) ;
abovei = i ;
}
}
}
* aboveip = abovei ;
* abovep = above ;
* belowip = belowi ;
* belowp = below ;
//printf("above.%d below.%d\n",abovei,belowi);
return ( abovei > = 0 ? abovei : belowi ) ;
}
cJSON * iguana_inputjson ( bits256 txid , int32_t vout , uint8_t * spendscript , int32_t spendlen )
{
char hexstr [ IGUANA_MAXSCRIPTSIZE * 2 + 1 ] ; cJSON * sobj , * item = cJSON_CreateObject ( ) ;
jaddbits256 ( item , " txid " , txid ) ;
jaddnum ( item , " vout " , vout ) ;
sobj = cJSON_CreateObject ( ) ;
init_hexbytes_noT ( hexstr , spendscript , spendlen ) ;
jaddstr ( sobj , " hex " , hexstr ) ;
jadd ( item , " scriptPubKey " , sobj ) ;
return ( item ) ;
}
cJSON * iguana_RTinputsjson ( struct supernet_info * myinfo , struct iguana_info * coin , uint64_t * totalp , uint64_t amount , struct iguana_outpoint * unspents , int32_t num , int32_t maxmode )
{
struct iguana_outpoint outpt ; cJSON * vins ; int32_t abovei , belowi , i , ind ; int64_t above , below , total = 0 , remains = amount ;
* totalp = 0 ;
vins = cJSON_CreateArray ( ) ;
for ( i = 0 ; i < num ; i + + )
{
below = above = 0 ;
if ( iguana_RTbestunspent ( myinfo , coin , & abovei , & above , & belowi , & below , unspents , num , remains , maxmode ) < 0 )
{
printf ( " error finding unspent i.%d of %d, %.8f vs %.8f \n " , i , num , dstr ( remains ) , dstr ( amount ) ) ;
free_json ( vins ) ;
return ( 0 ) ;
}
if ( belowi < 0 | | ( num = = 0 & & abovei > = 0 ) )
ind = abovei ;
else ind = belowi ;
outpt = unspents [ ind ] ;
memset ( & unspents [ ind ] , 0 , sizeof ( unspents [ ind ] ) ) ;
jaddi ( vins , iguana_inputjson ( outpt . txid , outpt . vout , outpt . spendscript , outpt . spendlen ) ) ;
total + = outpt . value ;
remains - = outpt . value ;
//printf("%s value %.8f -> remains %.8f\n",coinaddr,dstr(value),dstr(remains));
if ( remains < = 0 )
break ;
}
* totalp = total ;
return ( vins ) ;
}
char * iguana_signrawtx ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t height , bits256 * signedtxidp , int32_t * completedp , cJSON * vins , char * rawtx , cJSON * privkeys , struct vin_info * V )
{
char * signedtx = 0 ; struct iguana_msgtx msgtx ; int32_t numinputs , flagV = 0 , flag = 0 ;
* completedp = 0 ;
if ( privkeys = = 0 )
privkeys = iguana_privkeysjson ( myinfo , coin , vins ) , flag = 1 ;
if ( ( numinputs = cJSON_GetArraySize ( vins ) ) > 0 & & privkeys ! = 0 )
{
memset ( & msgtx , 0 , sizeof ( msgtx ) ) ;
if ( V = = 0 )
V = calloc ( numinputs , sizeof ( * V ) ) , flagV = 1 ;
//printf("SIGN.(%s) priv.(%s) %llx %llx\n",jprint(vins,0),jprint(privkeys,0),(long long)V->signers[0].privkey.txid,(long long)V->signers[1].privkey.txid);
if ( V ! = 0 )
{
if ( iguana_signrawtransaction ( myinfo , coin , height , & msgtx , & signedtx , signedtxidp , V , numinputs , rawtx , vins , privkeys ) > 0 )
* completedp = 1 ;
else printf ( " signrawtransaction incomplete \n " ) ;
//for (i=0; i<msgtx.tx_in; i++)
// if ( msgtx.vins[i].redeemscript != 0 )
// free(msgtx.vins[i].redeemscript), msgtx.vins[i].redeemscript = 0;
if ( flagV ! = 0 )
free ( V ) ;
}
if ( flag ! = 0 )
free_json ( privkeys ) ;
}
//char str[65]; printf("completed.%d %s signed.(%s)\n",*completedp,bits256_str(str,*signedtxidp),signedtx!=0?signedtx:"");
return ( signedtx ) ;
}
bits256 iguana_sendrawtransaction ( struct supernet_info * myinfo , struct iguana_info * coin , char * signedtx )
{
bits256 txid , checktxid ; uint8_t * serialized ; int32_t i , len , n ; struct iguana_peer * addr ; cJSON * vals ; char * str ;
len = ( int32_t ) strlen ( signedtx ) > > 1 ;
serialized = calloc ( 1 , sizeof ( struct iguana_msghdr ) + len ) ;
decode_hex ( & serialized [ sizeof ( struct iguana_msghdr ) ] , len , signedtx ) ;
txid = bits256_doublesha256 ( 0 , & serialized [ sizeof ( struct iguana_msghdr ) ] , len ) ;
if ( coin - > FULLNODE < 0 | | coin - > notarychain > = 0 )
{
if ( coin - > FULLNODE < 0 )
str = dpow_sendrawtransaction ( myinfo , coin , signedtx ) ;
else str = _dex_sendrawtransaction ( myinfo , coin - > symbol , signedtx ) ;
if ( str ! = 0 )
{
if ( is_hexstr ( str , 0 ) = = sizeof ( checktxid ) * 2 )
{
decode_hex ( checktxid . bytes , sizeof ( checktxid ) , str ) ;
if ( bits256_cmp ( txid , checktxid ) = = 0 )
{
free ( str ) ;
return ( txid ) ;
}
}
free ( str ) ;
memset ( txid . bytes , 0 , sizeof ( txid ) ) ;
return ( txid ) ;
}
}
if ( coin - > peers ! = 0 & & ( n = coin - > peers - > numranked ) > 0 )
{
for ( i = 0 ; i < 8 & & i < n ; i + + )
{
if ( ( addr = coin - > peers - > ranked [ i ] ) ! = 0 & & addr - > dead = = 0 & & addr - > usock > = 0 )
iguana_queue_send ( addr , 0 , serialized , " tx " , len ) ;
}
}
else
{
vals = cJSON_CreateObject ( ) ;
jaddstr ( vals , " symbol " , coin - > symbol ) ;
if ( ( str = gecko_sendrawtransaction ( myinfo , coin - > symbol , serialized , len , txid , vals , signedtx ) ) ! = 0 )
free ( str ) ;
free_json ( vals ) ;
}
free ( serialized ) ;
return ( txid ) ;
}
uint64_t iguana_interest ( struct supernet_info * myinfo , struct iguana_info * coin , bits256 txid , int32_t vout , uint64_t value )
{
char * retstr ; int32_t height ; cJSON * retjson ; struct iguana_txid T , * tx ;
int32_t minutes ; uint64_t numerator = 0 , denominator = 0 , interest = 0 ;
if ( coin - > FULLNODE < 0 ) // komodod is running
{
if ( ( retjson = dpow_gettxout ( myinfo , coin , txid , vout ) ) ! = 0 )
{
interest = jdouble ( retjson , " interest " ) * SATOSHIDEN ;
free_json ( retjson ) ;
}
}
else if ( coin - > FULLNODE = = 0 ) // basilisk mode -> use DEX* API
{
if ( ( retstr = _dex_gettxout ( myinfo , coin - > symbol , txid , vout ) ) ! = 0 )
{
if ( ( retjson = cJSON_Parse ( retstr ) ) ! = 0 )
{
interest = jdouble ( retjson , " interest " ) * SATOSHIDEN ;
free_json ( retjson ) ;
}
free ( retstr ) ;
}
}
else // we have it local
{
if ( ( tx = iguana_txidfind ( coin , & height , & T , txid , coin - > bundlescount ) ) ! = 0 & & tx - > locktime > LOCKTIME_THRESHOLD )
{
if ( ( minutes = ( ( uint32_t ) time ( NULL ) - 60 - tx - > locktime ) / 60 ) > = 60 )
{
denominator = ( ( ( uint64_t ) 365 * 24 * 60 ) / minutes ) ;
if ( denominator = = 0 )
denominator = 1 ; // max KOMODO_INTEREST per transfer, do it at least annually!
if ( value > 25000LL * SATOSHIDEN & & height > 155949 )
{
numerator = ( value / 20 ) ; // assumes 5%!
interest = ( numerator / denominator ) ;
}
else if ( value > = 10 * SATOSHIDEN )
{
numerator = ( value * KOMODO_INTEREST ) ;
interest = ( numerator / denominator ) / SATOSHIDEN ;
}
fprintf ( stderr , " komodo_interest %lld %.8f nLockTime.%u tiptime.%u minutes.%d interest %lld %.8f (%llu / %llu) \n " , ( long long ) value , ( double ) value / SATOSHIDEN , tx - > locktime , ( uint32_t ) time ( NULL ) , minutes , ( long long ) interest , ( double ) interest / SATOSHIDEN , ( long long ) numerator , ( long long ) denominator ) ;
}
}
}
char str [ 65 ] ; printf ( " interest for %s.v%d %.8f %.8f \n " , bits256_str ( str , txid ) , vout , dstr ( value ) , dstr ( interest ) ) ;
return ( interest ) ;
}
uint64_t iguana_interests ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * vins )
{
int32_t i , n ; cJSON * item ; uint64_t value , interest = 0 ;
if ( is_cJSON_Array ( vins ) ! = 0 & & ( n = cJSON_GetArraySize ( vins ) ) > 0 )
{
for ( i = 0 ; i < n ; i + + )
{
item = jitem ( vins , i ) ;
if ( ( value = jdouble ( item , " value " ) * SATOSHIDEN ) = = 0 )
value = jdouble ( item , " amount " ) * SATOSHIDEN ;
interest + = iguana_interest ( myinfo , coin , jbits256 ( item , " txid " ) , jint ( item , " vout " ) , value ) ;
}
}
return ( interest ) ;
}
char * iguana_calcrawtx ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * * vinsp , cJSON * txobj , int64_t satoshis , char * changeaddr , int64_t txfee , cJSON * addresses , int32_t minconf , uint8_t * opreturn , int32_t oplen , int64_t burnamount , char * remoteaddr , struct vin_info * V , int32_t maxmode )
{
uint8_t addrtype , rmd160 [ 20 ] , spendscript [ IGUANA_MAXSCRIPTSIZE ] ; char * coinaddr ; int32_t allocflag = 0 , max , i , j , m , n , num , spendlen ; char * spendscriptstr , * rawtx = 0 ; bits256 txid ; cJSON * vins = 0 , * array , * item ; uint64_t value , avail = 0 , total , change , interest ; struct iguana_outpoint * unspents = 0 ;
* vinsp = 0 ;
max = 0 ; //10000;
satoshis + = burnamount ;
if ( ( n = cJSON_GetArraySize ( addresses ) ) = = 0 )
return ( 0 ) ;
for ( i = 0 ; i < n ; i + + )
{
coinaddr = jstri ( addresses , i ) ;
if ( ( array = basilisk_unspents ( myinfo , coin , coinaddr ) ) ! = 0 )
{
//printf("unspents.(%s) %s\n",coinaddr,jprint(array,0));
if ( ( m = cJSON_GetArraySize ( array ) ) > 0 )
{
for ( j = 0 ; j < m ; j + + )
{
item = jitem ( array , j ) ;
if ( coin - > FULLNODE ! = 0 & & is_cJSON_False ( jobj ( item , " spendable " ) ) ! = 0 )
continue ;
if ( ( spendscriptstr = jstr ( item , " scriptPubKey " ) ) = = 0 )
{
printf ( " no spendscriptstr.(%s) \n " , jprint ( item , 0 ) ) ;
continue ;
}
unspents = realloc ( unspents , ( 1 + max ) * sizeof ( * unspents ) ) ;
value = jdouble ( item , " amount " ) * SATOSHIDEN ;
if ( jdouble ( item , " interest " ) ! = 0 )
printf ( " utxo has interest of %.8f \n " , jdouble ( item , " interest " ) ) ;
iguana_outptset ( myinfo , coin , & unspents [ max + + ] , jbits256 ( item , " txid " ) , jint ( item , " vout " ) , value , spendscriptstr ) ;
avail + = value ;
}
}
free_json ( array ) ;
}
}
if ( unspents = = 0 )
return ( 0 ) ;
num = max ;
/*unspents = calloc(max,sizeof(*unspents));
if ( ( num = iguana_RTunspentslists ( myinfo , coin , & avail , unspents , max , satoshis + txfee , minconf , addresses , remoteaddr ) ) < = 0 )
{
free ( unspents ) ;
return ( 0 ) ;
} */
printf ( " avail %.8f satoshis %.8f, txfee %.8f burnamount %.8f vin0.scriptlen %d \n " , dstr ( avail ) , dstr ( satoshis ) , dstr ( txfee ) , dstr ( burnamount ) , unspents [ 0 ] . spendlen ) ;
if ( txobj ! = 0 & & avail > = satoshis + txfee )
{
if ( ( vins = iguana_RTinputsjson ( myinfo , coin , & total , satoshis + txfee , unspents , num , maxmode ) ) ! = 0 )
{
if ( strcmp ( coin - > symbol , " KMD " ) = = 0 )
{
if ( ( interest = iguana_interests ( myinfo , coin , vins ) ) ! = 0 )
{
total + = interest ;
printf ( " boost total by interest %.8f \n " , dstr ( interest ) ) ;
}
}
if ( total < ( satoshis + txfee ) )
{
free_json ( vins ) ;
free ( unspents ) ;
printf ( " insufficient total %.8f vs (%.8f + %.8f) \n " , dstr ( total ) , dstr ( satoshis ) , dstr ( txfee ) ) ;
return ( 0 ) ;
}
if ( ( change = ( total - ( satoshis + txfee ) ) ) > 10000 & & ( changeaddr = = 0 | | changeaddr [ 0 ] = = 0 ) )
{
printf ( " no changeaddr for %.8f \n " , dstr ( change ) ) ;
free_json ( vins ) ;
free ( unspents ) ;
return ( 0 ) ;
}
iguana_createvins ( myinfo , coin , txobj , vins ) ;
if ( change > 10000 )
{
if ( iguana_addressvalidate ( coin , & addrtype , changeaddr ) < 0 )
{
free_json ( vins ) ;
free ( unspents ) ;
printf ( " illegal destination address.(%s) \n " , changeaddr ) ;
return ( 0 ) ;
}
bitcoin_addr2rmd160 ( & addrtype , rmd160 , changeaddr ) ;
spendlen = bitcoin_standardspend ( spendscript , 0 , rmd160 ) ;
bitcoin_txoutput ( txobj , spendscript , spendlen , change ) ;
if ( opreturn ! = 0 )
{
int32_t i ;
for ( i = 0 ; i < oplen ; i + + )
printf ( " %02x " , opreturn [ i ] ) ;
printf ( " <- got opret \n " ) ;
bitcoin_txoutput ( txobj , opreturn , oplen , burnamount ) ;
}
}
if ( vins ! = 0 & & V = = 0 )
{
V = calloc ( cJSON_GetArraySize ( vins ) , sizeof ( * V ) ) , allocflag = 1 ;
//iguana_vinprivkeys(myinfo,coin,V,vins);
}
rawtx = bitcoin_json2hex ( myinfo , coin , & txid , txobj , V ) ;
if ( allocflag ! = 0 )
free ( V ) ;
}
}
free ( unspents ) ;
* vinsp = vins ;
return ( rawtx ) ;
}
void iguana_RTunspentslock ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * vins )
{
struct iguana_outpoint spentpt ; char coinaddr [ 64 ] ; int32_t i , RTspentflag , num , spentheight , lockedflag ;
if ( coin - > MAXPEERS = = 1 | | coin - > FULLNODE > 0 | | coin - > VALIDATENODE > 0 )
{
num = cJSON_GetArraySize ( vins ) ;
for ( i = 0 ; i < num ; i + + )
{
if ( iguana_RTinputaddress ( myinfo , coin , coinaddr , & spentpt , jitem ( vins , i ) ) ! = 0 )
iguana_RTutxofunc ( coin , & spentheight , & lockedflag , spentpt , & RTspentflag , 1 , 0 ) ; // last arg should be spentheight
}
}
}
char * sendtoaddress ( struct supernet_info * myinfo , struct iguana_info * coin , char * remoteaddr , char * destaddr , uint64_t satoshis , uint64_t txfee , char * comment , char * comment2 , int32_t minconf , char * account )
{
uint8_t addrtype , spendscript [ 1024 ] , rmd160 [ 20 ] ; int32_t completed ; char * retstr , spendscriptstr [ 4096 ] , * rawtx = 0 , * signedtx = 0 ; bits256 signedtxid , senttxid ; cJSON * retjson , * vins , * addresses , * valsobj ; uint32_t spendlen , locktime = 0 ; uint32_t basilisktag ; struct vin_info * V = 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 ( coin - > RTheight = = 0 & & coin - > FULLNODE ! = 0 )
return ( clonestr ( " { \" error \" : \" need to get to realtime blocks to send transaction \" } " ) ) ;
if ( account = = 0 | | account [ 0 ] = = 0 )
account = " * " ;
addresses = iguana_getaddressesbyaccount ( myinfo , coin , account ) ;
if ( coin - > changeaddr [ 0 ] = = 0 )
{
bitcoin_address ( coin - > changeaddr , coin - > chain - > pubtype , myinfo - > persistent_pubkey33 , 33 ) ;
printf ( " %s change %s \n " , coin - > symbol , coin - > changeaddr ) ;
}
if ( destaddr ! = 0 & & destaddr [ 0 ] ! = 0 & & satoshis ! = 0 )
{
if ( iguana_addressvalidate ( coin , & addrtype , destaddr ) < 0 )
return ( clonestr ( " { \" error \" : \" invalid coin address \" } " ) ) ;
bitcoin_addr2rmd160 ( & addrtype , rmd160 , destaddr ) ;
spendlen = bitcoin_standardspend ( spendscript , 0 , rmd160 ) ;
init_hexbytes_noT ( spendscriptstr , spendscript , spendlen ) ;
basilisktag = ( uint32_t ) rand ( ) ;
valsobj = cJSON_CreateObject ( ) ;
jadd ( valsobj , " addresses " , addresses ) ;
jaddstr ( valsobj , " coin " , coin - > symbol ) ;
jaddstr ( valsobj , " changeaddr " , coin - > changeaddr ) ;
jaddstr ( valsobj , " spendscript " , spendscriptstr ) ;
jadd64bits ( valsobj , " satoshis " , satoshis ) ;
jadd64bits ( valsobj , " txfee " , txfee ) ;
jaddnum ( valsobj , " minconf " , minconf ) ;
jaddnum ( valsobj , " basilisktag " , basilisktag ) ;
jaddnum ( valsobj , " locktime " , locktime ) ;
jaddnum ( valsobj , " timeout " , 30000 ) ;
if ( 0 & & comment ! = 0 & & is_hexstr ( comment , 0 ) > 0 )
jaddstr ( valsobj , " opreturn " , comment ) ;
if ( ( retstr = basilisk_bitcoinrawtx ( myinfo , coin , remoteaddr , basilisktag , jint ( valsobj , " timeout " ) , valsobj , V ) ) ! = 0 )
{
if ( ( retjson = cJSON_Parse ( retstr ) ) ! = 0 )
{
if ( ( rawtx = jstr ( retjson , " rawtx " ) ) ! = 0 & & ( vins = jobj ( retjson , " vins " ) ) ! = 0 )
{
if ( ( signedtx = iguana_signrawtx ( myinfo , coin , coin - > blocks . hwmchain . height , & signedtxid , & completed , vins , rawtx , 0 , V ) ) ! = 0 )
{
iguana_RTunspentslock ( myinfo , coin , vins ) ;
retjson = cJSON_CreateObject ( ) ;
jaddbits256 ( retjson , " result " , signedtxid ) ;
jaddstr ( retjson , " signedtx " , signedtx ) ;
jadd ( retjson , " complete " , completed ! = 0 ? jtrue ( ) : jfalse ( ) ) ;
if ( completed ! = 0 )
{
senttxid = iguana_sendrawtransaction ( myinfo , coin , signedtx ) ;
if ( bits256_cmp ( senttxid , signedtxid ) = = 0 )
{
jaddstr ( retjson , " sendrawtransaction " , " success " ) ;
iguana_unspents_mark ( myinfo , coin , vins ) ;
} else jaddbits256 ( retjson , " senderror " , senttxid ) ;
}
free_json ( vins ) ;
free ( signedtx ) ;
return ( jprint ( retjson , 1 ) ) ;
}
else
{
free_json ( vins ) ;
return ( clonestr ( " { \" error \" : \" couldnt sign rawtx \" } " ) ) ;
}
}
free_json ( retjson ) ;
}
free ( retstr ) ;
return ( clonestr ( " { \" error \" : \" couldnt create rawtx \" } " ) ) ;
} else return ( clonestr ( " { \" error \" : \" couldnt create rawtx \" } " ) ) ;
}
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 ( ) ; bits256 txid ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( coin - > notarychain > = 0 & & coin - > FULLNODE = = 0 )
return ( _dex_sendrawtransaction ( myinfo , coin - > symbol , rawtx ) ) ;
txid = iguana_sendrawtransaction ( myinfo , coin , rawtx ) ;
jaddbits256 ( retjson , " result " , txid ) ;
return ( jprint ( retjson , 1 ) ) ;
}
STRING_ARG ( bitcoinrpc , submitblock , rawbytes )
{
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
cJSON * retjson = cJSON_CreateObject ( ) ;
// send to all peers
return ( jprint ( retjson , 1 ) ) ;
}
ZERO_ARGS ( iguana , makekeypair )
{
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
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 ( myinfo , privkey , 1 ) ) ;
return ( jprint ( retjson , 1 ) ) ;
}
STRING_ARG ( bitcoinrpc , validatepubkey , pubkeystr )
{
uint8_t pubkey [ 65 ] , addrtype = 0 ; int32_t plen ; char coinaddr [ 128 ] , * str ; cJSON * retjson ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
plen = ( int32_t ) strlen ( pubkeystr ) > > 1 ;
if ( plen > = 33 & & 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 , 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 ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( scriptstr ! = 0 & & 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 ) ) ;
//printf("create M.%d of N.%d (%s)\n",M,n,jprint(pubkeys,0));
V . M = M , V . N = n ;
pkjson = cJSON_CreateArray ( ) ;
addresses = cJSON_CreateArray ( ) ;
for ( i = 0 ; i < n ; i + + )
{
if ( ( pkstr = jstr ( jitem ( pubkeys , i ) , 0 ) ) ! = 0 )
{
if ( iguana_pubkeyget ( myinfo , coin , V . signers [ i ] . pubkey , pkstr ) < 0 )
break ;
if ( ( plen = bitcoin_pubkeylen ( V . signers [ i ] . pubkey ) ) < = 0 )
break ;
bitcoin_address ( V . signers [ i ] . coinaddr , coin - > chain - > 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 ) ;
}
//printf("CREATEMULTISIG.(%s)\n",jprint(retjson,0));
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 )
{
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 firstslot , minconf , scriptlen , unspentind , height , spentheight = - 1 ; struct iguana_RTtxid * ptr ; uint64_t RTspend , value ; struct iguana_ramchaindata * rdata ; struct iguana_pkhash * P ; struct iguana_txid * T ; struct iguana_unspent * U ; struct iguana_outpoint outpt ; struct iguana_ramchain * ramchain ; cJSON * scriptobj , * retjson = cJSON_CreateObject ( ) ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( coin ! = 0 )
{
if ( coin - > notarychain > = 0 & & coin - > FULLNODE = = 0 )
return ( _dex_gettxout ( myinfo , coin - > symbol , txid , vout ) ) ;
if ( ( value = _RTgettxout ( coin , & ptr , & height , & scriptlen , script , rmd160 , coinaddr , txid , vout , mempool ) ) > 0 )
{
jaddbits256 ( retjson , " bestblock " , coin - > blocks . hwmchain . RO . hash2 ) ;
jaddnum ( retjson , " bestheight " , coin - > blocks . hwmchain . height ) ;
jaddnum ( retjson , " height " , height ) ;
jaddbits256 ( retjson , " txid " , txid ) ;
jaddnum ( retjson , " vout " , vout ) ;
jaddnum ( retjson , " confirmations " , coin - > blocks . hwmchain . height - height + 1 ) ;
jaddnum ( retjson , " value " , dstr ( value ) ) ;
jaddnum ( retjson , " amount " , dstr ( value ) ) ;
if ( strcmp ( coin - > symbol , " KMD " ) = = 0 )
jaddnum ( retjson , " interest " , dstr ( iguana_interest ( myinfo , coin , txid , vout , value ) ) ) ;
if ( ( height % coin - > chain - > bundlesize ) = = 0 & & vout = = 0 )
jadd ( retjson , " coinbase " , jtrue ( ) ) ;
else jadd ( retjson , " coinbase " , jfalse ( ) ) ;
asmstr [ 0 ] = 0 ;
if ( ( scriptobj = iguana_scriptobj ( coin , rmd160 , coinaddr , asmstr , script , scriptlen ) ) ! = 0 )
jadd ( retjson , " scriptPubKey " , scriptobj ) ;
return ( jprint ( retjson , 1 ) ) ;
}
minconf = ( mempool ! = 0 ) ? 0 : 1 ;
if ( iguana_RTunspentindfind ( myinfo , coin , & outpt , 0 , 0 , 0 , 0 , & height , txid , vout , coin - > bundlescount - 1 , 0 ) = = 0 & & outpt . isptr = = 0 )
{
unspentind = outpt . unspentind ;
if ( height > = 0 & & height < coin - > longestchain & & ( bp = coin - > bundles [ height / coin - > chain - > bundlesize ] ) ! = 0 )
{
ramchain = & bp - > ramchain ;
if ( ( rdata = ramchain - > H . data ) ! = 0 )
{
U = RAMCHAIN_PTR ( rdata , Uoffset ) ;
P = RAMCHAIN_PTR ( rdata , Poffset ) ;
T = RAMCHAIN_PTR ( rdata , Toffset ) ;
RTspend = 0 ;
memset ( & outpt , 0 , sizeof ( outpt ) ) ;
outpt . hdrsi = bp - > hdrsi ;
outpt . unspentind = unspentind ;
if ( iguana_markedunspents_find ( coin , & firstslot , txid , vout ) < 0 & & iguana_RTspentflag ( myinfo , coin , & RTspend , & spentheight , ramchain , outpt , 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_RTunspentjson ( myinfo , coin , outpt , T [ U [ unspentind ] . txidind ] . txid , unspentind - T [ U [ unspentind ] . txidind ] . firstvout , U [ unspentind ] . value , & U [ unspentind ] , rmd160 , coinaddr , pubkey33 , spentheight , remoteaddr ) ) ;
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 ) ) ;
}
bits256 iguana_messagehash2 ( char * message , char * messagemagic )
{
int32_t n , len ; uint8_t * messagebuf ; bits256 hash2 ;
n = ( int32_t ) strlen ( message ) > > 1 ;
len = ( int32_t ) strlen ( messagemagic ) ;
if ( message [ 0 ] = = ' 0 ' & & message [ 1 ] = = ' x ' & & is_hexstr ( message + 2 , n - 2 ) > 0 )
{
messagebuf = malloc ( n - 2 + len ) ;
memcpy ( messagebuf , messagemagic , len ) ;
decode_hex ( messagebuf + len , n - 2 , message + 2 ) ;
n - - ;
}
else
{
n < < = 1 ;
messagebuf = malloc ( n + len + 1 ) ;
memcpy ( messagebuf , messagemagic , len ) ;
strcpy ( ( void * ) & messagebuf [ len ] , message ) ;
//printf("MESSAGE.(%s)\n",(void *)messagebuf);
}
n + = len ;
hash2 = bits256_doublesha256 ( 0 , messagebuf , n ) ;
//for (i=0; i<sizeof(hash2); i++)
// revhash2.bytes[i] = hash2.bytes[sizeof(hash2) - 1 - i];
if ( messagebuf ! = ( void * ) message )
free ( messagebuf ) ;
return ( hash2 ) ;
}
TWO_STRINGS ( bitcoinrpc , signmessage , address , message )
{
bits256 privkey , hash2 ; int32_t len , siglen ; char sigstr [ 256 ] , sig65str [ 256 ] ; uint8_t sig [ 128 ] ; cJSON * retjson = cJSON_CreateObject ( ) ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( myinfo - > expiration = = 0 )
return ( clonestr ( " { \" error \" : \" need to unlock wallet \" } " ) ) ;
if ( coin ! = 0 )
{
privkey = iguana_str2priv ( myinfo , coin , address ) ;
if ( bits256_nonz ( privkey ) ! = 0 )
{
hash2 = iguana_messagehash2 ( message , coin - > chain - > messagemagic ) ;
if ( ( siglen = bitcoin_sign ( coin - > ctx , coin - > symbol , sig , hash2 , privkey , 1 ) ) > 0 )
{
sigstr [ 0 ] = sig65str [ 0 ] = 0 ;
len = nn_base64_encode ( sig , siglen , sig65str , sizeof ( sig65str ) ) ;
sig65str [ len ] = 0 ;
jaddstr ( retjson , " result " , sig65str ) ;
}
} 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 )
{
int32_t len , plen ; uint8_t sigbuf [ 256 ] , pubkey [ 65 ] ; char str [ 4096 ] ; bits256 hash2 ; cJSON * retjson = cJSON_CreateObject ( ) ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( strlen ( sig ) < sizeof ( sigbuf ) * 8 / 6 )
{
len = ( int32_t ) strlen ( sig ) ;
len = nn_base64_decode ( sig , len , sigbuf , sizeof ( sigbuf ) ) ;
//int32_t i; for (i=0; i<len; i++)
// printf("%02x",sigbuf[i]);
//printf(" siglen.%d [%d] address.(%s) sig.(%s) message.(%s)\n",len,sigbuf[0],address,sig,message);
hash2 = iguana_messagehash2 ( message , coin - > chain - > messagemagic ) ;
if ( bitcoin_recoververify ( myinfo - > ctx , coin - > symbol , sigbuf , hash2 , pubkey , 0 ) = = 0 )
jadd ( retjson , " result " , jtrue ( ) ) ;
else jadd ( retjson , " result " , jfalse ( ) ) ;
jaddstr ( retjson , " coin " , coin - > symbol ) ;
jaddstr ( retjson , " address " , address ) ;
jaddstr ( retjson , " message " , message ) ;
if ( ( plen = bitcoin_pubkeylen ( pubkey ) ) > 0 )
{
init_hexbytes_noT ( str , pubkey , plen ) ;
jaddstr ( retjson , " pubkey " , str ) ;
}
init_hexbytes_noT ( str , sigbuf , len ) ;
jaddstr ( retjson , " sighex " , str ) ;
jaddbits256 ( retjson , " messagehash " , hash2 ) ;
return ( jprint ( retjson , 1 ) ) ;
} else return ( clonestr ( " { \" error \" : \" sig is too long \" } " ) ) ;
}
int64_t iguana_txdetails ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * item , bits256 txid , int32_t vout , int32_t height )
{
struct iguana_block * block ; bits256 hash2 ; uint64_t amount = 0 ; char coinaddr [ 64 ] , account [ 512 ] ;
/*{
" category " : " receive " ,
" amount " : 0.50000000 ,
" label " : " " ,
" confirmations " : 24466 ,
" blockhash " : " 00000000000000000517ce625737579f91162c46ad9eaccad0f52ca13715b156 " ,
" blockindex " : 78 ,
" blocktime " : 1448045745 ,
} */
jaddbits256 ( item , " txid " , txid ) ;
if ( vout > = 0 )
{
jaddnum ( item , " vout " , vout ) ;
if ( ( amount = iguana_txidamount ( myinfo , coin , coinaddr , txid , vout ) ) ! = 0 )
jaddnum ( item , " amount " , dstr ( amount ) ) ;
jaddstr ( item , " category " , iguana_txidcategory ( myinfo , coin , account , coinaddr , txid , vout ) ) ;
}
else
{
if ( vout = = - 1 )
jadd ( item , " coinbase " , jtrue ( ) ) ;
vout = 0 ;
}
if ( account [ 0 ] ! = 0 & & jobj ( item , " account " ) = = 0 )
jaddstr ( item , " account " , account ) ;
if ( coinaddr [ 0 ] ! = 0 )
jaddstr ( item , " address " , coinaddr ) ;
hash2 = iguana_blockhash ( coin , height ) ;
jaddbits256 ( item , " blockhash " , hash2 ) ;
if ( ( block = iguana_blockfind ( " rawtx " , coin , hash2 ) ) ! = 0 )
jaddnum ( item , " blocktime " , block - > RO . timestamp ) ;
jaddnum ( item , " height " , height ) ;
jaddnum ( item , " confirmations " , coin - > blocks . hwmchain . height - height ) ;
return ( amount ) ;
}
HASH_AND_INT ( bitcoinrpc , getrawtransaction , txid , verbose )
{
struct iguana_txid * tx , T ; char * txbytes ; bits256 checktxid ; int32_t len = 0 , height , extralen = 65536 ; cJSON * retjson , * txobj ; uint8_t * extraspace ; struct iguana_RTtxid * RTptr ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( coin - > notarychain > = 0 & & coin - > FULLNODE = = 0 )
return ( _dex_getrawtransaction ( myinfo , coin - > symbol , txid ) ) ;
HASH_FIND ( hh , coin - > RTdataset , txid . bytes , sizeof ( txid ) , RTptr ) ;
if ( RTptr ! = 0 & & RTptr - > rawtxbytes ! = 0 & & RTptr - > txlen > 0 )
{
checktxid = RTptr - > txid ;
height = RTptr - > height ;
len = RTptr - > txlen ;
memcpy ( coin - > blockspace , RTptr - > rawtxbytes , len ) ;
}
else if ( ( tx = iguana_txidfind ( coin , & height , & T , txid , coin - > bundlescount - 1 ) ) ! = 0 )
{
len = iguana_ramtxbytes ( coin , coin - > blockspace , coin - > blockspacesize , & checktxid , tx , height , 0 , 0 , 0 ) ;
}
retjson = cJSON_CreateObject ( ) ;
if ( len > 0 )
{
txbytes = calloc ( 1 , len * 2 + 1 ) ;
init_hexbytes_noT ( txbytes , coin - > blockspace , len ) ;
if ( verbose ! = 0 )
{
extraspace = calloc ( 1 , extralen ) ;
txobj = bitcoin_hex2json ( coin , coin - > blocks . hwmchain . height , & checktxid , 0 , txbytes , extraspace , extralen , 0 , 0 , 0 ) ;
free ( extraspace ) ;
free ( txbytes ) ;
if ( txobj ! = 0 )
{
iguana_txdetails ( myinfo , coin , txobj , checktxid , - 2 , height ) ;
return ( jprint ( txobj , 1 ) ) ;
}
}
jaddstr ( retjson , " result " , txbytes ) ;
char str [ 65 ] ; printf ( " txbytes.(%s) len.%d (%s) %s \n " , txbytes , len , jprint ( retjson , 0 ) , bits256_str ( str , checktxid ) ) ;
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 ( myinfo , coin , verbose ! = 0 ? retjson : 0 , data , datalen , txid ) ) ! = 0 )
{
jaddstr ( retjson , " result " , txbytes ) ;
jaddbits256 ( retjson , " blockhash " , blockhash ) ;
jaddnum ( retjson , " height " , height ) ;
free ( txbytes ) ;
}
else if ( coin - > RTheight > 0 )
jaddstr ( retjson , " error " , " cant find txid in block " ) ;
else jaddstr ( retjson , " error " , " not in realtime mode yet " ) ;
free ( blockstr ) ;
free ( data ) ;
} else jaddstr ( retjson , " error " , " cant find blockhash " ) ;
return ( jprint ( retjson , 1 ) ) ;
}
}
if ( coin - > RTheight > 0 )
return ( clonestr ( " { \" error \" : \" cant find txid \" } " ) ) ;
else return ( clonestr ( " { \" error \" : \" not in realtime mode yet \" } " ) ) ;
}
int64_t iguana_lockval ( int32_t finalized , int64_t locktime )
{
int64_t lockval = - 1 ;
if ( finalized = = 0 )
return ( locktime ) ;
return ( lockval ) ;
}
char * iguana_validaterawtx ( struct supernet_info * myinfo , struct iguana_info * coin , int32_t height , struct iguana_msgtx * msgtx , uint8_t * extraspace , int32_t extralen , char * rawtx , int32_t mempool , int32_t suppress_pubkeys )
{
bits256 signedtxid , txid ; struct iguana_outpoint outpt ; struct iguana_msgvin vin ; cJSON * log , * vins , * vouts , * txobj , * retjson ; char * checkstr , * signedtx ; int32_t plen , finalized = 1 , i , len , maxsize , numinputs , numoutputs , complete ; struct vin_info * V ; uint8_t * serialized , * serialized2 ; uint32_t sigsize , pubkeysize , p2shsize , suffixlen ; int64_t inputsum , outputsum , lockval ;
retjson = cJSON_CreateObject ( ) ;
inputsum = outputsum = numinputs = numoutputs = 0 ;
if ( rawtx ! = 0 & & rawtx [ 0 ] ! = 0 & & coin ! = 0 )
{
if ( ( strlen ( rawtx ) & 1 ) ! = 0 )
return ( clonestr ( " { \" error \" : \" rawtx hex has odd length \" } " ) ) ;
memset ( msgtx , 0 , sizeof ( * msgtx ) ) ;
if ( ( txobj = bitcoin_hex2json ( coin , coin - > blocks . hwmchain . height , & msgtx - > txid , msgtx , rawtx , extraspace , extralen , 0 , 0 , suppress_pubkeys ) ) ! = 0 )
{
//printf("txobj.(%s)\n",jprint(txobj,0));
if ( 0 & & ( checkstr = bitcoin_json2hex ( myinfo , coin , & txid , txobj , 0 ) ) ! = 0 )
{
// no guarantee byte for byte identical tx is recreated
if ( strcmp ( rawtx , checkstr ) ! = 0 )
{
jaddstr ( retjson , " error " , " converting from hex2json and json2hex mismatch " ) ;
jaddstr ( retjson , " original " , rawtx ) ;
jaddstr ( retjson , " checkstr " , checkstr ) ;
for ( i = 0 ; rawtx [ i ] ! = 0 & & checkstr [ i ] ! = 0 ; i + + )
if ( rawtx [ i ] ! = checkstr [ i ] )
break ;
jaddnum ( retjson , " mismatch position " , i ) ;
jadd ( retjson , " origtx " , txobj ) ;
if ( 0 & & ( txobj = bitcoin_hex2json ( coin , coin - > blocks . hwmchain . height , & txid , msgtx , checkstr , extraspace , extralen , 0 , 0 , suppress_pubkeys ) ) ! = 0 )
jadd ( retjson , " checktx " , txobj ) ;
free ( checkstr ) ;
return ( jprint ( retjson , 1 ) ) ;
}
free ( checkstr ) ;
}
if ( ( vouts = jarray ( & numoutputs , txobj , " vout " ) ) > 0 )
{
struct iguana_msgvout vout ; uint8_t voutdata [ IGUANA_MAXSCRIPTSIZE ] ;
for ( i = 0 ; i < numoutputs ; i + + )
{
if ( iguana_parsevoutobj ( coin , voutdata , sizeof ( voutdata ) , & vout , jitem ( vouts , i ) ) > 0 )
outputsum + = vout . value ;
}
}
if ( ( vins = jarray ( & numinputs , txobj , " vin " ) ) > 0 )
{
maxsize = ( int32_t ) strlen ( rawtx ) ;
serialized = malloc ( maxsize ) ;
serialized2 = malloc ( maxsize ) ;
len = 0 ;
V = calloc ( numinputs , sizeof ( * V ) ) ;
for ( i = 0 ; i < numinputs ; i + + )
{
len + = iguana_parsevinobj ( myinfo , coin , & serialized [ len ] , maxsize - len , & vin , jitem ( vins , i ) , & V [ i ] ) ;
if ( iguana_RTunspentindfind ( myinfo , coin , & outpt , V [ i ] . coinaddr , V [ i ] . spendscript , & V [ i ] . spendlen , & V [ i ] . amount , & V [ i ] . height , msgtx - > vins [ i ] . prev_hash , msgtx - > vins [ i ] . prev_vout , coin - > bundlescount - 1 , mempool ) = = 0 )
{
V [ i ] . suppress_pubkeys = suppress_pubkeys ;
V [ i ] . unspentind = outpt . unspentind ;
inputsum + = V [ i ] . amount ;
msgtx - > vins [ i ] . spendscript = V [ i ] . spendscript ;
if ( ( msgtx - > vins [ i ] . spendlen = V [ i ] . spendlen ) = = 35 )
{
if ( ( plen = bitcoin_pubkeylen ( msgtx - > vins [ i ] . spendscript + 1 ) ) > 0 )
{
memcpy ( V [ i ] . signers [ 0 ] . pubkey , msgtx - > vins [ i ] . spendscript + 1 , plen ) ;
V [ i ] . suppress_pubkeys = 1 ;
}
}
V [ i ] . hashtype = iguana_vinscriptparse ( coin , & V [ i ] , & sigsize , & pubkeysize , & p2shsize , & suffixlen , msgtx - > vins [ i ] . vinscript , msgtx - > vins [ i ] . scriptlen ) ;
//if ( (V[i].signers[0].siglen= sigsize) > 0 )
// memcpy(V[i].signers[0].sig,msgtx->vins[i].vinscript+1,sigsize);
V [ i ] . userdatalen = suffixlen ;
memcpy ( V [ i ] . spendscript , msgtx - > vins [ i ] . spendscript , msgtx - > vins [ i ] . spendlen ) ;
V [ i ] . spendlen = msgtx - > vins [ i ] . spendlen ;
if ( msgtx - > vins [ i ] . sequence < IGUANA_SEQUENCEID_FINAL )
finalized = 0 ;
if ( V [ i ] . M = = 0 )
V [ i ] . M = 1 ;
if ( V [ i ] . N < V [ i ] . M )
V [ i ] . N = V [ i ] . M ;
//printf("V %dof%d %.8f (%s) spendscript.[%d] scriptlen.%d\n",V[i].M,V[i].N,dstr(V[i].amount),V[i].coinaddr,V[i].spendlen,V[i].spendlen);
} else printf ( " couldnt find spendscript \n " ) ;
}
complete = 0 ;
bitcoin_verifyvins ( coin , height , & signedtxid , & signedtx , msgtx , serialized2 , maxsize , V , 1 , 0 , suppress_pubkeys ) ;
msgtx - > txid = signedtxid ;
log = cJSON_CreateArray ( ) ;
lockval = iguana_lockval ( finalized , jint ( txobj , " locktime " ) ) ;
if ( iguana_interpreter ( coin , log , lockval , V , numinputs ) < 0 )
jaddstr ( retjson , " error " , " interpreter rejects tx " ) ;
else complete = 1 ;
jadd ( retjson , " interpreter " , log ) ;
jaddnum ( retjson , " complete " , complete ) ;
free ( serialized ) , free ( serialized2 ) ;
if ( signedtx ! = 0 )
free ( signedtx ) ;
}
}
//char str[65]; printf("got txid.(%s)\n",bits256_str(str,txid));
}
msgtx - > inputsum = inputsum ;
msgtx - > numinputs = numinputs ;
msgtx - > outputsum = outputsum ;
msgtx - > numoutputs = numoutputs ;
msgtx - > txfee = ( inputsum - outputsum ) ;
return ( jprint ( retjson , 1 ) ) ;
}
STRING_AND_INT ( bitcoinrpc , validaterawtransaction , rawtx , suppress )
{
uint8_t * extraspace ; int32_t extralen = 65536 ; char * retstr ; struct iguana_msgtx msgtx ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
extraspace = calloc ( 1 , extralen ) ;
retstr = iguana_validaterawtx ( myinfo , coin , coin - > blocks . hwmchain . height , & msgtx , extraspace , extralen , rawtx , 0 , suppress ) ;
free ( extraspace ) ;
return ( rawtx ) ;
}
int32_t iguana_validatesigs ( struct supernet_info * myinfo , struct iguana_info * coin , uint8_t * serialized , int32_t datalen )
{
uint8_t * extraspace ; cJSON * retjson ; int32_t extralen = 65536 ; char * retstr , * rawtx ; struct iguana_msgtx msgtx ; int32_t suppress = 0 , retval = - 1 ;
rawtx = calloc ( 1 , datalen * 2 + 1 ) ;
init_hexbytes_noT ( rawtx , serialized , datalen ) ;
extraspace = calloc ( 1 , extralen ) ;
for ( suppress = 0 ; suppress < 1 ; suppress + + )
{
if ( ( retstr = iguana_validaterawtx ( myinfo , coin , coin - > blocks . hwmchain . height , & msgtx , extraspace , extralen , rawtx , 0 , suppress ) ) ! = 0 )
{
if ( ( retjson = cJSON_Parse ( retstr ) ) ! = 0 )
{
if ( jobj ( retjson , " error " ) = = 0 )
{
retval = 0 ;
//char str[65]; printf("%s %s sigs validated\n",coin->symbol,bits256_str(str,msgtx.txid));
coin - > sigsvalidated + + ;
break ;
}
else
{
printf ( " ERROR.(%s) \n " , retstr ) ;
coin - > sigserrs + + ;
}
free_json ( retjson ) ;
}
free ( retstr ) ;
}
}
free ( rawtx ) ;
free ( extraspace ) ;
return ( retval ) ;
}
STRING_AND_INT ( bitcoinrpc , decoderawtransaction , rawtx , suppress )
{
cJSON * txobj = 0 ; bits256 txid ; uint8_t * extraspace ; int32_t extralen = 65536 ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( rawtx ! = 0 & & rawtx [ 0 ] ! = 0 )
{
if ( ( strlen ( rawtx ) & 1 ) ! = 0 )
return ( clonestr ( " { \" error \" : \" rawtx hex has odd length \" } " ) ) ;
extraspace = calloc ( 1 , extralen ) ;
txobj = bitcoin_hex2json ( coin , coin - > blocks . hwmchain . height , & txid , 0 , rawtx , extraspace , extralen , 0 , 0 , suppress ) ;
free ( extraspace ) ;
//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 )
{
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
return ( bitcoinrpc_getrawtransaction ( IGUANA_CALLARGS , txid , 1 ) ) ;
}
cJSON * iguana_createvins ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * txobj , cJSON * vins )
{
int32_t i , j , n , vout , p2shlen = 0 , spendlen = 0 , height ; uint64_t satoshis ; char coinaddr [ 128 ] , pubkeystr [ 256 ] , scriptstr [ IGUANA_MAXSCRIPTSIZE * 2 ] , * str , * hexstr ; cJSON * pubkeys , * item , * obj , * newvin , * newvins ; uint32_t sequenceid ; bits256 txid ; uint8_t spendscript [ IGUANA_MAXSCRIPTSIZE ] , redeemscript [ IGUANA_MAXSCRIPTSIZE ] ; struct iguana_waccount * wacct ; struct iguana_waddress * waddr ; struct iguana_outpoint outpt ;
newvins = cJSON_CreateArray ( ) ;
if ( ( n = cJSON_GetArraySize ( vins ) ) > 0 )
{
for ( i = 0 ; i < n ; i + + )
{
pubkeys = cJSON_CreateArray ( ) ;
newvin = cJSON_CreateObject ( ) ;
item = jitem ( vins , i ) ;
txid = jbits256 ( item , " txid " ) ;
vout = jint ( item , " vout " ) ;
jaddbits256 ( newvin , " txid " , txid ) ;
jaddnum ( newvin , " vout " , vout ) ;
p2shlen = spendlen = 0 ;
if ( ( ( str = jstr ( item , " scriptPub " ) ) ! = 0 | | ( str = jstr ( item , " scriptPubKey " ) ) ! = 0 ) & & is_hexstr ( str , ( int32_t ) strlen ( str ) ) > 0 )
{
spendlen = ( int32_t ) strlen ( str ) > > 1 ;
decode_hex ( spendscript , spendlen , str ) ;
}
else if ( ( ( obj = jobj ( item , " scriptPub " ) ) ! = 0 | | ( obj = jobj ( item , " scriptPubKey " ) ) ! = 0 ) & & ( hexstr = jstr ( obj , " hex " ) ) ! = 0 )
{
spendlen = ( int32_t ) strlen ( hexstr ) > > 1 ;
decode_hex ( spendscript , spendlen , hexstr ) ;
}
if ( coin - > FULLNODE = = 0 & & coin - > notarychain > = 0 )
{
char * retstr ; cJSON * txoutjson , * sobj , * array ; int32_t numaddrs ;
if ( ( retstr = _dex_gettxout ( myinfo , coin - > symbol , txid , vout ) ) ! = 0 )
{
// {"bestblock":"000000000000000002a530b32efce4cb4ee01b401d58592ce36939d84c9f94b9","confirmations":109,"value":0.00120000,"scriptPubKey":{"asm":"OP_DUP OP_HASH160 971f98b33fb838faee190e2fab799440d8c51702 OP_EQUALVERIFY OP_CHECKSIG","hex":"76a914971f98b33fb838faee190e2fab799440d8c5170288ac","reqSigs":1,"type":"pubkeyhash","addresses":["1En4tL4drN5qAZDtu1BCC7DThj58yrx7cX"]},"version":1,"coinbase":false,"randipbits":847292520,"coin":"BTC","tag":"18220985608713355389"}
if ( ( txoutjson = cJSON_Parse ( retstr ) ) ! = 0 )
{
if ( ( sobj = jobj ( txoutjson , " scriptPubKey " ) ) ! = 0 & & ( array = jarray ( & numaddrs , txoutjson , " addresses " ) ) ! = 0 )
{
for ( j = 0 ; j < numaddrs ; j + + )
{
if ( strlen ( jstri ( array , j ) ) < sizeof ( coinaddr ) - 1 )
{
if ( ( waddr = iguana_waddresssearch ( myinfo , & wacct , jstri ( array , j ) ) ) ! = 0 )
{
init_hexbytes_noT ( pubkeystr , waddr - > pubkey , bitcoin_pubkeylen ( waddr - > pubkey ) ) ;
jaddistr ( pubkeys , pubkeystr ) ;
//printf("pubkeys[%d] <- (%s)\n",j,pubkeystr);
}
}
}
}
free_json ( txoutjson ) ;
}
free ( retstr ) ;
}
}
else if ( iguana_RTunspentindfind ( myinfo , coin , & outpt , coinaddr , spendscript , & spendlen , & satoshis , & height , txid , vout , coin - > bundlescount - 1 , 0 ) = = 0 )
{
//printf("[%d] unspentind.%d (%s) spendlen.%d %.8f\n",height/coin->chain->bundlesize,unspentind,coinaddr,spendlen,dstr(satoshis));
if ( coinaddr [ 0 ] ! = 0 & & ( waddr = iguana_waddresssearch ( myinfo , & wacct , coinaddr ) ) ! = 0 )
{
init_hexbytes_noT ( pubkeystr , waddr - > pubkey , bitcoin_pubkeylen ( waddr - > pubkey ) ) ;
jaddistr ( pubkeys , pubkeystr ) ;
}
}
if ( spendlen > 0 )
{
init_hexbytes_noT ( scriptstr , spendscript , spendlen ) ;
jaddstr ( newvin , " scriptPubKey " , scriptstr ) ;
}
if ( ( str = jstr ( item , " redeemScript " ) ) ! = 0 )
{
p2shlen = ( int32_t ) strlen ( str ) > > 1 ;
decode_hex ( redeemscript , p2shlen , str ) ;
init_hexbytes_noT ( scriptstr , redeemscript , p2shlen ) ;
jaddstr ( newvin , " redeemScript " , scriptstr ) ;
}
if ( jint ( txobj , " locktime " ) > 0 )
sequenceid = ( uint32_t ) time ( NULL ) ; // any value < 0xfffffffe should be fine
else
{
if ( jobj ( item , " sequence " ) ! = 0 )
sequenceid = juint ( item , " sequence " ) ;
else sequenceid = 0xffffffff ;
}
jaddnum ( newvin , " sequence " , sequenceid ) ;
bitcoin_txinput ( coin , txobj , txid , vout , sequenceid , spendscript , spendlen , redeemscript , p2shlen , 0 , 0 , 0 , 0 ) ;
jadd ( newvin , " pubkeys " , pubkeys ) ;
jaddi ( newvins , newvin ) ;
}
}
return ( newvins ) ;
}
ARRAY_OBJ_INT ( bitcoinrpc , createrawtransaction , vins , vouts , locktime )
{
bits256 txid ; int32_t offset , spendlen = 0 , n ; uint8_t addrtype , rmd160 [ 20 ] , spendscript [ IGUANA_MAXSCRIPTSIZE ] ; uint64_t satoshis ; char * hexstr , * field , * txstr ; cJSON * txobj , * item , * obj , * retjson = cJSON_CreateObject ( ) ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( coin ! = 0 & & ( txobj = bitcoin_txcreate ( coin - > symbol , coin - > chain - > isPoS , locktime , 1 , 0 ) ) ! = 0 )
{
iguana_createvins ( myinfo , coin , txobj , vins ) ;
if ( ( n = cJSON_GetArraySize ( vouts ) ) > 0 )
{
if ( is_cJSON_Array ( vouts ) ! = 0 & & n = = 1 & & ( item = jitem ( vouts , 0 ) ) ! = 0 )
item = item - > child ;
else item = vouts - > child ;
while ( item ! = 0 )
{
if ( ( field = jfieldname ( item ) ) ! = 0 )
{
if ( strcmp ( field , " data " ) = = 0 )
{
if ( ( hexstr = jstr ( item , 0 ) ) ! = 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 = jdouble ( obj , 0 ) * SATOSHIDEN ;
else satoshis = 0 ;
bitcoin_txoutput ( txobj , spendscript + offset , spendlen , satoshis ) ;
}
}
break ;
}
else
{
if ( bitcoin_addr2rmd160 ( & addrtype , rmd160 , field ) = = sizeof ( rmd160 ) )
{
spendlen = bitcoin_standardspend ( spendscript , 0 , rmd160 ) ;
satoshis = jdouble ( item , 0 ) * SATOSHIDEN ;
bitcoin_txoutput ( txobj , spendscript , spendlen , satoshis ) ;
}
}
}
item = item - > next ;
}
}
if ( ( txstr = bitcoin_json2hex ( myinfo , coin , & txid , txobj , 0 ) ) ! = 0 )
{
jaddstr ( retjson , " result " , txstr ) ;
free ( txstr ) ;
}
}
return ( jprint ( retjson , 1 ) ) ;
}
cJSON * iguana_listunspents ( struct supernet_info * myinfo , struct iguana_info * coin , cJSON * array , int32_t minconf , int32_t maxconf , char * remoteaddr )
{
cJSON * retjson ; int32_t flag = 0 ;
if ( array = = 0 | | is_cJSON_Array ( array ) = = 0 | | cJSON_GetArraySize ( array ) < = 0 )
{
array = iguana_getaddressesbyaccount ( myinfo , coin , " * " ) ;
flag = 1 ;
//printf("listunspent.(%s)\n",jprint(array,0));
}
if ( minconf = = 0 )
minconf = 1 ;
if ( maxconf = = 0 )
maxconf = ( 1 < < 30 ) ;
retjson = iguana_RTlistunspent ( myinfo , coin , array , minconf , maxconf , remoteaddr , 0 ) ;
if ( array ! = 0 & & flag ! = 0 )
free_json ( array ) ;
return ( retjson ) ;
}
TWOINTS_AND_ARRAY ( bitcoinrpc , listunspent , minconf , maxconf , array )
{
//int32_t numrmds,numunspents=0; uint8_t *rmdarray; cJSON *retjson = cJSON_CreateArray();
cJSON * retjson ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
retjson = iguana_listunspents ( myinfo , coin , array , minconf , maxconf , remoteaddr ) ;
return ( jprint ( retjson , 1 ) ) ;
}
ZERO_ARGS ( bitcoinrpc , getrawchangeaddress )
{
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
cJSON * retjson = cJSON_CreateObject ( ) ;
jaddstr ( retjson , " result " , coin - > changeaddr ) ;
return ( jprint ( retjson , 1 ) ) ;
}
INT_AND_ARRAY ( bitcoinrpc , lockunspent , flag , array )
{
struct iguana_outpoint outpt ; int32_t RTspendflag , vout , i , n , height , spentheight , lockedflag ; cJSON * item , * retjson ; bits256 txid ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
retjson = cJSON_CreateObject ( ) ;
if ( array ! = 0 & & ( n = cJSON_GetArraySize ( array ) ) > 0 )
{
for ( i = 0 ; i < n ; i + + )
{
item = jitem ( array , i ) ;
if ( jobj ( item , " txid " ) ! = 0 & & jobj ( item , " vout " ) ! = 0 )
{
txid = jbits256 ( item , " txid " ) ;
vout = jint ( item , " vout " ) ;
if ( iguana_RTunspentindfind ( myinfo , coin , & outpt , 0 , 0 , 0 , 0 , & height , txid , vout , coin - > bundlescount - 1 , 0 ) = = 0 )
{
//outpt.hdrsi = height / coin->chain->bundlesize;
//outpt.unspentind = unspentind;
iguana_RTutxofunc ( coin , & spentheight , & lockedflag , outpt , & RTspendflag , ! flag , 0 ) ;
}
}
}
}
return ( jprint ( retjson , 1 ) ) ;
}
ZERO_ARGS ( bitcoinrpc , listlockunspent )
{
cJSON * array , * retjson ; //int32_t vout; //struct iguana_outpoint outpt;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
array = cJSON_CreateArray ( ) ;
retjson = cJSON_CreateObject ( ) ;
printf ( " need to port listlockunspent to new RT method \n " ) ;
jaddstr ( retjson , " error " , " need to port listlockunspent to new RT method " ) ;
/*if ( coin->utxotable != 0 )
{
HASH_ITER ( hh , coin - > utxotable , hhutxo , tmputxo )
{
item = cJSON_CreateObject ( ) ;
//if ( (vout= iguana_RTuvaltxid(myinfo,&txid,coin,hhutxo->outpt)) >= 0 )
{
jaddbits256 ( item , " txid " , txid ) ;
jaddnum ( item , " vout " , vout ) ;
jaddi ( array , item ) ;
}
}
} */
jadd ( retjson , " result " , array ) ;
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 )
{
char * retstr ;
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);
if ( ( retstr = sendtoaddress ( myinfo , coin , remoteaddr , address , amount * SATOSHIDEN , coin - > txfee , comment , comment2 , coin - > minconfirms , 0 ) ) ! = 0 )
printf ( " SEND.(%s) \n " , retstr ) ;
return ( retstr ) ;
}
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 , remoteaddr , toaddress , amount * SATOSHIDEN , coin - > txfee , 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 ;
retjson = cJSON_CreateArray ( ) ;
for ( required = i = 0 ; i < n ; i + + )
{
if ( item ! = 0 & & ( coinaddr = item - > string ) ! = 0 )
{
amount = jdouble ( item , 0 ) ;
val = amount * SATOSHIDEN ;
printf ( " (%s %.8f) " , coinaddr , dstr ( val ) ) ;
if ( ( str = sendtoaddress ( myinfo , coin , remoteaddr , coinaddr , val , coin - > txfee , comment , " " , minconf , fromaccount ) ) ! = 0 )
{
jaddistr ( retjson , str ) ;
}
required + = val ;
}
item = item - > next ;
}
printf ( " required %.8f \n " , dstr ( required ) ) ;
return ( jprint ( retjson , 1 ) ) ;
}
THREE_INTS ( iguana , splitfunds , satoshis , duplicates , sendflag )
{
char * rawtx ; uint8_t pubkey33 [ 33 ] ; int32_t completed ; cJSON * retjson , * addresses ; bits256 signedtxid ;
if ( remoteaddr ! = 0 )
return ( clonestr ( " { \" error \" : \" no remote \" } " ) ) ;
if ( myinfo - > expiration = = 0 )
return ( clonestr ( " { \" error \" : \" need to unlock wallet \" } " ) ) ;
if ( coin = = 0 )
return ( clonestr ( " { \" error \" : \" need active coin \" } " ) ) ;
retjson = cJSON_CreateObject ( ) ;
bitcoin_pubkey33 ( myinfo - > ctx , pubkey33 , myinfo - > persistent_priv ) ;
addresses = iguana_getaddressesbyaccount ( myinfo , coin , " * " ) ;
if ( ( rawtx = iguana_utxoduplicates ( myinfo , coin , pubkey33 , satoshis , duplicates , & completed , & signedtxid , sendflag , addresses ) ) ! = 0 )
{
jaddstr ( retjson , " result " , rawtx ) ;
jaddbits256 ( retjson , " txid " , signedtxid ) ;
jadd ( retjson , " completed " , completed ! = 0 ? jtrue ( ) : jfalse ( ) ) ;
free ( rawtx ) ;
} else jaddstr ( retjson , " error " , " couldnt create duplicates tx " ) ;
if ( addresses ! = 0 )
free_json ( addresses ) ;
return ( jprint ( retjson , 1 ) ) ;
}
# include "../includes/iguana_apiundefs.h"