You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
672 lines
28 KiB
672 lines
28 KiB
/******************************************************************************
|
|
* Copyright © 2014-2016 The SuperNET Developers. *
|
|
* *
|
|
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
|
|
* the top-level directory of this distribution for the individual copyright *
|
|
* holder information and the developer policies on copyright and licensing. *
|
|
* *
|
|
* Unless otherwise agreed in a custom licensing agreement, no part of the *
|
|
* SuperNET software, including this file may be copied, modified, propagated *
|
|
* or distributed except according to the terms contained in the LICENSE file *
|
|
* *
|
|
* Removal or modification of this copyright notice is prohibited. *
|
|
* *
|
|
******************************************************************************/
|
|
|
|
#include "iguana777.h"
|
|
|
|
char *iguana_APIrequest(struct iguana_info *coin,bits256 blockhash,bits256 txid,int32_t seconds)
|
|
{
|
|
int32_t i,len; char *retstr = 0; uint8_t serialized[1024]; char str[65];
|
|
coin->APIblockhash = blockhash;
|
|
coin->APItxid = txid;
|
|
printf("request block.(%s) txid.%llx\n",bits256_str(str,blockhash),(long long)txid.txid);
|
|
if ( (len= iguana_getdata(coin,serialized,MSG_BLOCK,&blockhash,1)) > 0 )
|
|
{
|
|
for (i=0; 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,coin,&wacct,str)) != 0 )
|
|
privkey = waddr->privkey;
|
|
else memset(privkey.bytes,0,sizeof(privkey));
|
|
}
|
|
}
|
|
return(privkey);
|
|
}
|
|
|
|
int32_t iguana_pubkeyget(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *pubkey33,char *str)
|
|
{
|
|
bits256 privkey,pubkey; uint8_t pubkeydata[128]; int32_t len,plen= -1; struct iguana_waccount *wacct; struct iguana_waddress *waddr;
|
|
len = (int32_t)strlen(str);
|
|
if ( is_hexstr(str,len) == 0 )
|
|
{
|
|
if ( (waddr= iguana_waddresssearch(myinfo,coin,&wacct,str)) != 0 )
|
|
{
|
|
if ( (plen= bitcoin_pubkeylen(waddr->pubkey)) > 0 )
|
|
memcpy(pubkeydata,waddr->pubkey,plen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
decode_hex(pubkeydata,len,str);
|
|
plen = bitcoin_pubkeylen(pubkeydata);
|
|
}
|
|
if ( plen <= 0 )
|
|
{
|
|
privkey = iguana_str2priv(myinfo,coin,str);
|
|
if ( bits256_nonz(privkey) == 0 )
|
|
return(-1);
|
|
else
|
|
{
|
|
pubkey = bitcoin_pubkey33(pubkeydata,privkey);
|
|
if ( bits256_nonz(pubkey) == 0 )
|
|
return(-1);
|
|
}
|
|
}
|
|
if ( (plen= bitcoin_pubkeylen(pubkeydata)) > 0 )
|
|
memcpy(pubkey33,pubkeydata,plen);
|
|
return(0);
|
|
}
|
|
|
|
cJSON *iguana_p2shjson(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *retjson,struct iguana_waddress *waddr)
|
|
{
|
|
char str[4096]; uint8_t type; struct iguana_waccount *wacct; bits256 debugtxid; struct vin_info V; cJSON *privkeys,*pubkeys,*addresses; int32_t i,plen;
|
|
if ( retjson == 0 )
|
|
retjson = cJSON_CreateObject();
|
|
init_hexbytes_noT(str,waddr->redeemScript,waddr->scriptlen);
|
|
jaddstr(retjson,"redeemScript",str);
|
|
memset(debugtxid.bytes,0,sizeof(debugtxid));
|
|
if ( (type= iguana_calcrmd160(coin,0,&V,waddr->redeemScript,waddr->scriptlen, debugtxid,-1,0xffffffff)) >= 0 )
|
|
{
|
|
privkeys = cJSON_CreateArray();
|
|
pubkeys = cJSON_CreateArray();
|
|
addresses = cJSON_CreateArray();
|
|
for (i=0; i<V.N; i++)
|
|
{
|
|
if ( V.signers[i].coinaddr[0] != 0 && (waddr= iguana_waddresssearch(myinfo,coin,&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=0;
|
|
if ( (asmtype= iguana_calcrmd160(coin,asmstr,&V,script,scriptlen,rand256(1),1,0xffffffff)) >= 0 )
|
|
{
|
|
if ( asmstr != 0 && asmstr[0] != 0 )
|
|
jaddstr(scriptobj,"asm",asmstr);
|
|
jaddnum(scriptobj,"iguanatype",asmtype);
|
|
jaddnum(scriptobj,"scriptlen",scriptlen);
|
|
jaddnum(scriptobj,"reqSigs",V.M);
|
|
if ( (plen= bitcoin_pubkeylen(V.signers[0].pubkey)) > 0 )
|
|
{
|
|
init_hexbytes_noT(pubkeystr,V.signers[0].pubkey,plen);
|
|
jaddstr(scriptobj,"pubkey",pubkeystr);
|
|
init_hexbytes_noT(rmdstr,V.signers[0].rmd160,20);
|
|
jaddstr(scriptobj,"rmd160",rmdstr);
|
|
}
|
|
addrobj = cJSON_CreateArray();
|
|
for (i=0; i<V.N; i++)
|
|
jaddistr(addrobj,V.signers[i].coinaddr);
|
|
jadd(scriptobj,"addresses",addrobj);
|
|
if ( V.p2shlen != 0 )
|
|
jaddstr(scriptobj,"p2sh",V.coinaddr);
|
|
strcpy(coinaddr,V.coinaddr);
|
|
memcpy(rmd160,V.rmd160,20);
|
|
}
|
|
return(scriptobj);
|
|
}
|
|
|
|
char *sendtoaddress(struct supernet_info *myinfo,struct iguana_info *coin,char *coinaddr,double amount,char *comment,char *comment2,int32_t minconf,char *account)
|
|
{
|
|
uint8_t addrtype,rmd160[20]; int32_t numwaddrs; struct iguana_waddress **waddrs;
|
|
//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 && amount > 0. )
|
|
{
|
|
if ( iguana_addressvalidate(coin,&addrtype,rmd160,coinaddr) < 0 )
|
|
return(clonestr("{\"error\":\"invalid coin address\"}"));
|
|
numwaddrs = iguana_unspentslists(myinfo,coin,(struct iguana_waddress **)coin->blockspace,(int32_t)(sizeof(coin->blockspace)/sizeof(*waddrs)),amount,minconf,0);
|
|
|
|
printf("need to generate send %.8f to %s [%s] [%s] using numaddrs.%d\n",dstr(amount),coinaddr,comment!=0?comment:"",comment2!=0?comment2:"",numwaddrs);
|
|
}
|
|
return(clonestr("{\"error\":\"need address and amount\"}"));
|
|
}
|
|
|
|
#include "../includes/iguana_apidefs.h"
|
|
#include "../includes/iguana_apideclares.h"
|
|
|
|
STRING_AND_INT(bitcoinrpc,sendrawtransaction,rawtx,allowhighfees)
|
|
{
|
|
cJSON *retjson = cJSON_CreateObject();
|
|
// send to 2 peers
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
STRING_ARG(bitcoinrpc,submitblock,rawbytes)
|
|
{
|
|
cJSON *retjson = cJSON_CreateObject();
|
|
// send to all peers
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
ZERO_ARGS(bitcoinrpc,makekeypair)
|
|
{
|
|
bits256 privkey; char str[67]; cJSON *retjson = cJSON_CreateObject();
|
|
privkey = rand256(1);
|
|
jaddstr(retjson,"result","success");
|
|
jaddstr(retjson,"privkey",bits256_str(str,privkey));
|
|
jadd(retjson,"rosetta",SuperNET_rosettajson(privkey,1));
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
STRING_ARG(bitcoinrpc,validatepubkey,pubkeystr)
|
|
{
|
|
uint8_t rmd160[20],pubkey[65],addrtype = 0; int32_t plen; char coinaddr[128],*str; cJSON *retjson;
|
|
plen = (int32_t)strlen(pubkeystr) >> 1;
|
|
if ( plen <= 65 && coin != 0 && coin->chain != 0 )
|
|
{
|
|
addrtype = coin->chain->pubtype;
|
|
decode_hex(pubkey,plen,pubkeystr);
|
|
if ( (str= bitcoin_address(coinaddr,addrtype,pubkey,plen)) != 0 )
|
|
{
|
|
if ( iguana_addressvalidate(coin,&addrtype,rmd160,coinaddr) < 0 )
|
|
return(clonestr("{\"error\":\"invalid coin address\"}"));
|
|
retjson = cJSON_CreateObject();
|
|
jaddstr(retjson,"result","success");
|
|
jaddstr(retjson,"pubkey",pubkeystr);
|
|
jaddstr(retjson,"address",coinaddr);
|
|
jaddstr(retjson,"coin",coin->symbol);
|
|
return(jprint(retjson,1));
|
|
}
|
|
}
|
|
return(clonestr("{\"error\":\"invalid pubkey\"}"));
|
|
}
|
|
|
|
STRING_ARG(bitcoinrpc,decodescript,scriptstr)
|
|
{
|
|
int32_t scriptlen; uint8_t script[IGUANA_MAXSCRIPTSIZE],rmd160[20]; char coinaddr[128],asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; cJSON *scriptobj,*retjson = cJSON_CreateObject();
|
|
if ( coin != 0 && (scriptlen= (int32_t)strlen(scriptstr)>>1) < sizeof(script) )
|
|
{
|
|
decode_hex(script,scriptlen,scriptstr);
|
|
if ( (scriptobj= iguana_scriptobj(coin,rmd160,coinaddr,asmstr,script,scriptlen)) != 0 )
|
|
jadd(retjson,"result",scriptobj);
|
|
}
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
INT_ARRAY_STRING(bitcoinrpc,createmultisig,M,pubkeys,ignore)
|
|
{
|
|
cJSON *retjson,*pkjson,*addresses; uint8_t script[2048],p2sh_rmd160[20]; char pubkeystr[256],msigaddr[64],*pkstr,scriptstr[sizeof(script)*2+1]; struct vin_info V; int32_t i,plen,len,n = cJSON_GetArraySize(pubkeys);
|
|
if ( remoteaddr != 0 )
|
|
return(clonestr("{\"error\":\"no remote\"}"));
|
|
if ( n < 0 || n > 16 || M < 0 || M > n )
|
|
return(clonestr("{\"error\":\"illegal number of pubkeys\"}"));
|
|
memset(&V,0,sizeof(V));
|
|
V.M = M, V.N = n;
|
|
pkjson = cJSON_CreateArray();
|
|
addresses = cJSON_CreateArray();
|
|
for (i=0; 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);
|
|
}
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
INT_ARRAY_STRING(bitcoinrpc,addmultisigaddress,M,pubkeys,account) //
|
|
{
|
|
cJSON *retjson,*tmpjson,*setjson=0; char *retstr,*str=0,*msigaddr,*redeemScript;
|
|
if ( remoteaddr != 0 )
|
|
return(clonestr("{\"error\":\"no remote\"}"));
|
|
if ( myinfo->expiration == 0 )
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
myinfo->expiration++;
|
|
if ( (retstr= bitcoinrpc_createmultisig(IGUANA_CALLARGS,M,pubkeys,account)) != 0 )
|
|
{
|
|
//printf("CREATEMULTISIG.(%s)\n",retstr);
|
|
if ( (retjson= cJSON_Parse(retstr)) != 0 )
|
|
{
|
|
if ( (msigaddr= jstr(retjson,"address")) != 0 )
|
|
{
|
|
if ( (redeemScript= jstr(retjson,"redeemScript")) == 0 || (str= setaccount(myinfo,coin,0,account,msigaddr,redeemScript)) == 0 || (setjson= cJSON_Parse(str)) == 0 || jobj(setjson,"error") != 0 )
|
|
{
|
|
if ( jobj(retjson,"result") != 0 )
|
|
jdelete(retjson,"result");
|
|
if ( jobj(retjson,"error") == 0 )
|
|
jaddstr(retjson,"error","couldnt add multisig address to account");
|
|
}
|
|
else
|
|
{
|
|
tmpjson = cJSON_CreateObject();
|
|
jaddstr(tmpjson,"result",msigaddr);
|
|
free_json(retjson);
|
|
free(retstr);
|
|
retjson = tmpjson;
|
|
}
|
|
}
|
|
if ( setjson != 0 )
|
|
free_json(setjson);
|
|
if ( str != 0 )
|
|
free(str);
|
|
return(jprint(retjson,1));
|
|
} else return(clonestr("{\"error\":\"couldnt parse retstr from createmultisig\"}"));
|
|
} else return(clonestr("{\"error\":\"no retstr from createmultisig\"}"));
|
|
}
|
|
|
|
HASH_AND_TWOINTS(bitcoinrpc,gettxout,txid,vout,mempool)
|
|
{
|
|
uint8_t script[IGUANA_MAXSCRIPTSIZE],rmd160[20],pubkey33[33]; char coinaddr[128],asmstr[IGUANA_MAXSCRIPTSIZE*2+1]; struct iguana_bundle *bp; int32_t minconf,scriptlen,unspentind,height,spentheight; int64_t RTspend; struct iguana_ramchaindata *rdata; struct iguana_pkhash *P; struct iguana_txid *T; struct iguana_unspent *U; struct iguana_ramchain *ramchain; cJSON *scriptobj,*retjson = cJSON_CreateObject();
|
|
if ( coin != 0 )
|
|
{
|
|
minconf = (mempool != 0) ? 0 : 1;
|
|
if ( (unspentind= iguana_unspentindfind(coin,&height,txid,vout,coin->bundlescount-1)) != 0 )
|
|
{
|
|
if ( height >= 0 && height < coin->longestchain && (bp= coin->bundles[height / coin->chain->bundlesize]) != 0 )
|
|
{
|
|
ramchain = (bp == coin->current) ? &coin->RTramchain : &bp->ramchain;
|
|
if ( (rdata= ramchain->H.data) != 0 )
|
|
{
|
|
U = (void *)(long)((long)rdata + rdata->Uoffset);
|
|
P = (void *)(long)((long)rdata + rdata->Poffset);
|
|
T = (void *)(long)((long)rdata + rdata->Toffset);
|
|
RTspend = 0;
|
|
if ( iguana_spentflag(coin,&RTspend,&spentheight,ramchain,bp->hdrsi,unspentind,height,minconf,coin->longestchain,U[unspentind].value) == 0 )
|
|
{
|
|
jaddbits256(retjson,"bestblock",coin->blocks.hwmchain.RO.hash2);
|
|
jaddnum(retjson,"bestheight",coin->blocks.hwmchain.height);
|
|
jaddnum(retjson,"height",height);
|
|
jaddnum(retjson,"confirmations",coin->blocks.hwmchain.height - height + 1);
|
|
jaddnum(retjson,"value",dstr(U[unspentind].value));
|
|
memset(rmd160,0,sizeof(rmd160));
|
|
memset(pubkey33,0,sizeof(pubkey33));
|
|
memset(coinaddr,0,sizeof(coinaddr));
|
|
if ( (scriptlen= iguana_voutscript(coin,bp,script,0,&U[unspentind],&P[U[unspentind].pkind],vout)) > 0 )
|
|
{
|
|
if ( (scriptobj= iguana_scriptobj(coin,rmd160,coinaddr,asmstr,script,scriptlen)) != 0 )
|
|
jadd(retjson,"scriptPubKey",scriptobj);
|
|
}
|
|
jadd(retjson,"iguana",iguana_unspentjson(myinfo,coin,bp->hdrsi,unspentind,T,&U[unspentind],rmd160,coinaddr,pubkey33));
|
|
if ( (height % coin->chain->bundlesize) == 0 && vout == 0 )
|
|
jadd(retjson,"coinbase",jtrue());
|
|
else jadd(retjson,"coinbase",jfalse());
|
|
}
|
|
else
|
|
{
|
|
jaddstr(retjson,"error","already spent");
|
|
jaddnum(retjson,"spentheight",spentheight);
|
|
jaddnum(retjson,"unspentind",unspentind);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
TWO_STRINGS(bitcoinrpc,signmessage,address,messagestr)
|
|
{
|
|
bits256 privkey; int32_t n,len,siglen; char sigstr[256],sig64str[256]; uint8_t sig[128],*message=0; cJSON *retjson = cJSON_CreateObject();
|
|
if ( coin != 0 )
|
|
{
|
|
privkey = iguana_str2priv(myinfo,coin,address);
|
|
if ( bits256_nonz(privkey) != 0 )
|
|
{
|
|
n = (int32_t)strlen(messagestr) >> 1;
|
|
if ( messagestr[0] == '0' && messagestr[1] == 'x' && is_hexstr(messagestr+2,n-2) > 0 )
|
|
{
|
|
message = malloc(n-2);
|
|
decode_hex(message,n-2,messagestr+2);
|
|
n -= 2;
|
|
} else message = (uint8_t *)messagestr, n <<= 1;
|
|
if ( (siglen= bitcoin_sign(sig,sizeof(sig),message,n,privkey)) > 0 )
|
|
{
|
|
sigstr[0] = sig64str[0] = 0;
|
|
//init_hexbytes_noT(sigstr,sig,siglen);
|
|
len = nn_base64_encode(sig,siglen,sig64str,sizeof(sig64str));
|
|
sig64str[len++] = '=';
|
|
sig64str[len++] = 0;
|
|
jaddstr(retjson,"result",sig64str);
|
|
}
|
|
if ( message != (void *)messagestr )
|
|
free(message);
|
|
} else jaddstr(retjson,"error","invalid address (can be wif, wallet address or privkey hex)");
|
|
}
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
THREE_STRINGS(bitcoinrpc,verifymessage,address,sig,message)
|
|
{
|
|
cJSON *retjson = cJSON_CreateObject();
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
HASH_AND_INT(bitcoinrpc,getrawtransaction,txid,verbose)
|
|
{
|
|
struct iguana_txid *tx,T; char *txbytes; bits256 checktxid; int32_t len,height; cJSON *retjson;
|
|
if ( (tx= iguana_txidfind(coin,&height,&T,txid,coin->bundlescount-1)) != 0 )
|
|
{
|
|
retjson = cJSON_CreateObject();
|
|
if ( (len= iguana_ramtxbytes(coin,coin->blockspace,sizeof(coin->blockspace),&checktxid,tx,height,0,0,0)) > 0 )
|
|
{
|
|
txbytes = calloc(1,len*2+1);
|
|
init_hexbytes_noT(txbytes,coin->blockspace,len);
|
|
jaddstr(retjson,"result",txbytes);
|
|
printf("txbytes.(%s) len.%d (%s)\n",txbytes,len,jprint(retjson,0));
|
|
free(txbytes);
|
|
return(jprint(retjson,1));
|
|
}
|
|
else if ( height >= 0 )
|
|
{
|
|
if ( coin->APIblockstr != 0 )
|
|
jaddstr(retjson,"error","already have pending request");
|
|
else
|
|
{
|
|
int32_t datalen; uint8_t *data; char *blockstr; bits256 blockhash;
|
|
blockhash = iguana_blockhash(coin,height);
|
|
if ( (blockstr= iguana_APIrequest(coin,blockhash,txid,2)) != 0 )
|
|
{
|
|
datalen = (int32_t)(strlen(blockstr) >> 1);
|
|
data = malloc(datalen);
|
|
decode_hex(data,datalen,blockstr);
|
|
if ( (txbytes= iguana_txscan(coin,verbose != 0 ? retjson : 0,data,datalen,txid)) != 0 )
|
|
{
|
|
jaddstr(retjson,"result",txbytes);
|
|
jaddbits256(retjson,"blockhash",blockhash);
|
|
jaddnum(retjson,"height",height);
|
|
free(txbytes);
|
|
} else jaddstr(retjson,"error","cant find txid in block");
|
|
free(blockstr);
|
|
free(data);
|
|
} else jaddstr(retjson,"error","cant find blockhash");
|
|
return(jprint(retjson,1));
|
|
}
|
|
} else printf("height.%d\n",height);
|
|
}
|
|
return(clonestr("{\"error\":\"cant find txid\"}"));
|
|
}
|
|
|
|
STRING_ARG(bitcoinrpc,decoderawtransaction,rawtx)
|
|
{
|
|
cJSON *txobj = 0; bits256 txid;
|
|
if ( rawtx != 0 && rawtx[0] != 0 )
|
|
{
|
|
if ( (strlen(rawtx) & 1) != 0 )
|
|
return(clonestr("{\"error\":\"rawtx hex has odd length\"}"));
|
|
txobj = bitcoin_hex2json(coin,&txid,0,rawtx);
|
|
//char str[65]; printf("got txid.(%s)\n",bits256_str(str,txid));
|
|
}
|
|
if ( txobj == 0 )
|
|
txobj = cJSON_CreateObject();
|
|
return(jprint(txobj,1));
|
|
}
|
|
|
|
HASH_ARG(bitcoinrpc,gettransaction,txid)
|
|
{
|
|
return(bitcoinrpc_getrawtransaction(IGUANA_CALLARGS,txid,1));
|
|
}
|
|
|
|
ARRAY_OBJ_INT(bitcoinrpc,createrawtransaction,vins,vouts,locktime)
|
|
{
|
|
bits256 txid; int32_t vout,offset,spendlen=0,p2shlen=0,i,n; uint32_t sequenceid; uint8_t addrtype,rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],redeemscript[IGUANA_MAXSCRIPTSIZE]; uint64_t satoshis; char *hexstr,*str,*field,*txstr; cJSON *txobj,*item,*obj,*retjson = cJSON_CreateObject();
|
|
if ( coin != 0 && (txobj= bitcoin_createtx(coin,locktime)) != 0 )
|
|
{
|
|
if ( (n= cJSON_GetArraySize(vins)) > 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(vins,i);
|
|
p2shlen = spendlen = 0;
|
|
if ( (str= jstr(item,"scriptPubKey")) != 0 || (str= jstr(item,"scriptPubkey")) != 0 )
|
|
{
|
|
spendlen = (int32_t)strlen(str) >> 1;
|
|
decode_hex(spendscript,spendlen,str);
|
|
}
|
|
if ( (str= jstr(item,"redeemScript")) != 0 )
|
|
{
|
|
p2shlen = (int32_t)strlen(str) >> 1;
|
|
decode_hex(redeemscript,p2shlen,str);
|
|
}
|
|
vout = jint(item,"vout");
|
|
if ( jobj(item,"sequenceid") != 0 )
|
|
sequenceid = juint(item,"sequenceid");
|
|
else sequenceid = 0xffffffff;
|
|
txid = jbits256(item,"txid");
|
|
bitcoin_addinput(coin,txobj,txid,vout,sequenceid,spendscript,spendlen,redeemscript,p2shlen);
|
|
}
|
|
}
|
|
if ( (n= cJSON_GetArraySize(vouts)) > 0 )
|
|
{
|
|
item = vouts->child;
|
|
while ( item != 0 )
|
|
{
|
|
if ( (field= jfieldname(item)) != 0 )
|
|
{
|
|
if ( strcmp(field,"data") == 0 )
|
|
{
|
|
if ( (hexstr= jstr(item,"data")) != 0 )
|
|
{
|
|
spendlen = (int32_t)strlen(hexstr) >> 1;
|
|
offset = 0;
|
|
if ( is_hexstr(hexstr,spendlen) > 0 )
|
|
{
|
|
decode_hex(spendscript+4,spendlen,hexstr);
|
|
spendscript[3] = SCRIPT_OPRETURN;
|
|
spendlen++;
|
|
/* 1-75 0x01-0x4b (special) data The next opcode bytes is data to be pushed onto the stack
|
|
OP_PUSHDATA1 76 0x4c (special) data The next byte contains the number of bytes to be pushed onto the stack.
|
|
OP_PUSHDATA2 77 0x4d*/
|
|
if ( spendlen < 76 )
|
|
{
|
|
spendscript[2] = spendlen;
|
|
offset = 2;
|
|
spendlen++;
|
|
}
|
|
else if ( spendlen <= 0xff )
|
|
{
|
|
spendscript[2] = spendlen;
|
|
spendscript[1] = 0x4c;
|
|
offset = 1;
|
|
spendlen += 2;
|
|
}
|
|
else if ( spendlen <= 0xffff )
|
|
{
|
|
spendscript[2] = ((spendlen >> 8) & 0xff);
|
|
spendscript[1] = (spendlen & 0xff);
|
|
spendscript[0] = 0x4d;
|
|
offset = 0;
|
|
spendlen += 3;
|
|
}
|
|
else continue;
|
|
if ( (obj= jobj(item,"amount")) != 0 )
|
|
satoshis = get_API_float(obj) * SATOSHIDEN;
|
|
else satoshis = 0;
|
|
bitcoin_addoutput(coin,txobj,spendscript+offset,spendlen,satoshis);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
if ( bitcoin_addr2rmd160(&addrtype,rmd160,field) == sizeof(rmd160) )
|
|
{
|
|
spendlen = bitcoin_standardspend(spendscript,0,rmd160);
|
|
satoshis = get_API_float(item) * SATOSHIDEN;
|
|
bitcoin_addoutput(coin,txobj,spendscript,spendlen,satoshis);
|
|
}
|
|
}
|
|
}
|
|
item = item->next;
|
|
}
|
|
}
|
|
if ( (txstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 )
|
|
{
|
|
jaddstr(retjson,"result",txstr);
|
|
free(txstr);
|
|
}
|
|
}
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
TWOINTS_AND_ARRAY(bitcoinrpc,listunspent,minconf,maxconf,array)
|
|
{
|
|
int32_t numrmds; uint8_t *rmdarray; cJSON *retjson = cJSON_CreateArray();
|
|
if ( minconf == 0 )
|
|
minconf = 1;
|
|
if ( maxconf == 0 )
|
|
maxconf = 9999999;
|
|
rmdarray = iguana_rmdarray(coin,&numrmds,array,0);
|
|
iguana_unspents(myinfo,coin,retjson,minconf,maxconf,rmdarray,numrmds,0,0,0);
|
|
if ( rmdarray != 0 )
|
|
free(rmdarray);
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
INT_AND_ARRAY(bitcoinrpc,lockunspent,flag,array)
|
|
{
|
|
cJSON *retjson = cJSON_CreateObject();
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
ZERO_ARGS(bitcoinrpc,listlockunspent)
|
|
{
|
|
cJSON *retjson = cJSON_CreateObject();
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
DOUBLE_ARG(bitcoinrpc,settxfee,amount)
|
|
{
|
|
cJSON *retjson;
|
|
if ( remoteaddr != 0 )
|
|
return(clonestr("{\"error\":\"no remote\"}"));
|
|
if ( myinfo->expiration == 0 )
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
myinfo->expiration++;
|
|
coin->txfee_perkb = amount * SATOSHIDEN;
|
|
retjson = cJSON_CreateObject();
|
|
jadd(retjson,"result",jtrue());
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
S_D_SS(bitcoinrpc,sendtoaddress,address,amount,comment,comment2)
|
|
{
|
|
if ( remoteaddr != 0 )
|
|
return(clonestr("{\"error\":\"no remote\"}"));
|
|
if ( myinfo->expiration == 0 )
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
myinfo->expiration++;
|
|
iguana_unspentset(myinfo,coin);
|
|
return(sendtoaddress(myinfo,coin,address,amount,comment,comment2,coin->minconfirms,0));
|
|
}
|
|
|
|
SS_D_I_SS(bitcoinrpc,sendfrom,fromaccount,toaddress,amount,minconf,comment,comment2)
|
|
{
|
|
if ( remoteaddr != 0 )
|
|
return(clonestr("{\"error\":\"no remote\"}"));
|
|
if ( myinfo->expiration == 0 )
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
myinfo->expiration++;
|
|
iguana_unspentset(myinfo,coin);
|
|
return(sendtoaddress(myinfo,coin,toaddress,amount,comment,comment2,minconf,fromaccount));
|
|
}
|
|
|
|
S_A_I_S(bitcoinrpc,sendmany,fromaccount,payments,minconf,comment)
|
|
{
|
|
cJSON *retjson,*item; int32_t i,n; char *coinaddr,*str; int64_t required,val; double amount;
|
|
if ( remoteaddr != 0 )
|
|
return(clonestr("{\"error\":\"no remote\"}"));
|
|
if ( myinfo->expiration == 0 )
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}"));
|
|
myinfo->expiration++;
|
|
iguana_unspentset(myinfo,coin);
|
|
n = cJSON_GetArraySize(payments);
|
|
item = payments->child;
|
|
for (required=i=0; 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,coinaddr,amount,comment,"",minconf,fromaccount)) != 0 )
|
|
{
|
|
free(str);
|
|
}
|
|
required += val;
|
|
}
|
|
item = item->next;
|
|
}
|
|
printf("required %.8f\n",dstr(required));
|
|
retjson = cJSON_CreateObject();
|
|
return(jprint(retjson,1));
|
|
}
|
|
|
|
#include "../includes/iguana_apiundefs.h"
|
|
|