Hush Full Node software. We were censored from Github, this is where all development happens now.
https://hush.is
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.
1597 lines
51 KiB
1597 lines
51 KiB
// Copyright (c) 2016-2024 The Hush developers
|
|
// Distributed under the GPLv3 software license, see the accompanying
|
|
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
/******************************************************************************
|
|
* Copyright © 2014-2020 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <memory.h>
|
|
#include "cJSON.c"
|
|
|
|
bits256 zeroid;
|
|
|
|
int32_t unstringbits(char *buf,uint64_t bits)
|
|
{
|
|
int32_t i;
|
|
for (i=0; i<8; i++,bits>>=8)
|
|
if ( (buf[i]= (char)(bits & 0xff)) == 0 )
|
|
break;
|
|
buf[i] = 0;
|
|
return(i);
|
|
}
|
|
|
|
uint64_t stringbits(char *str)
|
|
{
|
|
uint64_t bits = 0;
|
|
if ( str == 0 )
|
|
return(0);
|
|
int32_t i,n = (int32_t)strlen(str);
|
|
if ( n > 8 )
|
|
n = 8;
|
|
for (i=n-1; i>=0; i--)
|
|
bits = (bits << 8) | (str[i] & 0xff);
|
|
//printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits);
|
|
return(bits);
|
|
}
|
|
|
|
char hexbyte(int32_t c)
|
|
{
|
|
c &= 0xf;
|
|
if ( c < 10 )
|
|
return('0'+c);
|
|
else if ( c < 16 )
|
|
return('a'+c-10);
|
|
else return(0);
|
|
}
|
|
|
|
int32_t _unhex(char c)
|
|
{
|
|
if ( c >= '0' && c <= '9' )
|
|
return(c - '0');
|
|
else if ( c >= 'a' && c <= 'f' )
|
|
return(c - 'a' + 10);
|
|
else if ( c >= 'A' && c <= 'F' )
|
|
return(c - 'A' + 10);
|
|
return(-1);
|
|
}
|
|
|
|
int32_t is_hexstr(char *str,int32_t n)
|
|
{
|
|
int32_t i;
|
|
if ( str == 0 || str[0] == 0 )
|
|
return(0);
|
|
for (i=0; str[i]!=0; i++)
|
|
{
|
|
if ( n > 0 && i >= n )
|
|
break;
|
|
if ( _unhex(str[i]) < 0 )
|
|
break;
|
|
}
|
|
if ( n == 0 )
|
|
return(i);
|
|
return(i == n);
|
|
}
|
|
|
|
int32_t unhex(char c)
|
|
{
|
|
int32_t hex;
|
|
if ( (hex= _unhex(c)) < 0 )
|
|
{
|
|
//printf("unhex: illegal hexchar.(%c)\n",c);
|
|
}
|
|
return(hex);
|
|
}
|
|
|
|
unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); }
|
|
|
|
int32_t decode_hex(unsigned char *bytes,int32_t n,char *hex)
|
|
{
|
|
int32_t adjust,i = 0;
|
|
//printf("decode.(%s)\n",hex);
|
|
if ( is_hexstr(hex,n) <= 0 )
|
|
{
|
|
memset(bytes,0,n);
|
|
return(n);
|
|
}
|
|
if ( hex[n-1] == '\n' || hex[n-1] == '\r' )
|
|
hex[--n] = 0;
|
|
if ( hex[n-1] == '\n' || hex[n-1] == '\r' )
|
|
hex[--n] = 0;
|
|
if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) )
|
|
{
|
|
if ( n > 0 )
|
|
{
|
|
bytes[0] = unhex(hex[0]);
|
|
printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex));
|
|
}
|
|
bytes++;
|
|
hex++;
|
|
adjust = 1;
|
|
} else adjust = 0;
|
|
if ( n > 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
bytes[i] = _decode_hex(&hex[i*2]);
|
|
}
|
|
//bytes[i] = 0;
|
|
return(n + adjust);
|
|
}
|
|
|
|
int32_t init_hexbytes_noT(char *hexbytes,unsigned char *message,long len)
|
|
{
|
|
int32_t i;
|
|
if ( len <= 0 )
|
|
{
|
|
hexbytes[0] = 0;
|
|
return(1);
|
|
}
|
|
for (i=0; i<len; i++)
|
|
{
|
|
hexbytes[i*2] = hexbyte((message[i]>>4) & 0xf);
|
|
hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf);
|
|
//printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]);
|
|
}
|
|
hexbytes[len*2] = 0;
|
|
//printf("len.%ld\n",len*2+1);
|
|
return((int32_t)len*2+1);
|
|
}
|
|
|
|
long _stripwhite(char *buf,int accept)
|
|
{
|
|
int32_t i,j,c;
|
|
if ( buf == 0 || buf[0] == 0 )
|
|
return(0);
|
|
for (i=j=0; buf[i]!=0; i++)
|
|
{
|
|
buf[j] = c = buf[i];
|
|
if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') )
|
|
j++;
|
|
}
|
|
buf[j] = 0;
|
|
return(j);
|
|
}
|
|
|
|
char *clonestr(char *str)
|
|
{
|
|
char *clone;
|
|
if ( str == 0 || str[0]==0)
|
|
{
|
|
printf("warning cloning nullstr.%p\n",str);
|
|
//#ifdef __APPLE__
|
|
// while ( 1 ) sleep(1);
|
|
//#endif
|
|
str = (char *)"<nullstr>";
|
|
}
|
|
clone = (char *)malloc(strlen(str)+16);
|
|
strcpy(clone,str);
|
|
return(clone);
|
|
}
|
|
|
|
int32_t safecopy(char *dest,char *src,long len)
|
|
{
|
|
int32_t i = -1;
|
|
if ( src != 0 && dest != 0 && src != dest )
|
|
{
|
|
if ( dest != 0 )
|
|
memset(dest,0,len);
|
|
for (i=0; i<len&&src[i]!=0; i++)
|
|
dest[i] = src[i];
|
|
if ( i == len )
|
|
{
|
|
printf("safecopy: %s too long %ld\n",src,len);
|
|
//printf("divide by zero! %d\n",1/zeroval());
|
|
#ifdef __APPLE__
|
|
//getchar();
|
|
#endif
|
|
return(-1);
|
|
}
|
|
dest[i] = 0;
|
|
}
|
|
return(i);
|
|
}
|
|
|
|
char *bits256_str(char hexstr[65],bits256 x)
|
|
{
|
|
init_hexbytes_noT(hexstr,x.bytes,sizeof(x));
|
|
return(hexstr);
|
|
}
|
|
|
|
int64_t conv_floatstr(char *numstr)
|
|
{
|
|
double val,corr;
|
|
val = atof(numstr);
|
|
corr = (val < 0.) ? -0.50000000001 : 0.50000000001;
|
|
return((int64_t)(val * SATOSHIDEN + corr));
|
|
}
|
|
|
|
char *nonportable_path(char *str)
|
|
{
|
|
int32_t i;
|
|
for (i=0; str[i]!=0; i++)
|
|
if ( str[i] == '/' )
|
|
str[i] = '\\';
|
|
return(str);
|
|
}
|
|
|
|
char *portable_path(char *str)
|
|
{
|
|
#ifdef _WIN32
|
|
return(nonportable_path(str));
|
|
#else
|
|
#ifdef __PNACL
|
|
/*int32_t i,n;
|
|
if ( str[0] == '/' )
|
|
return(str);
|
|
else
|
|
{
|
|
n = (int32_t)strlen(str);
|
|
for (i=n; i>0; i--)
|
|
str[i] = str[i-1];
|
|
str[0] = '/';
|
|
str[n+1] = 0;
|
|
}*/
|
|
#endif
|
|
return(str);
|
|
#endif
|
|
}
|
|
|
|
void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep)
|
|
{
|
|
FILE *fp;
|
|
long filesize,buflen = *allocsizep;
|
|
uint8_t *buf = *bufp;
|
|
*lenp = 0;
|
|
if ( (fp= fopen(portable_path(fname),"rb")) != 0 )
|
|
{
|
|
fseek(fp,0,SEEK_END);
|
|
filesize = ftell(fp);
|
|
if ( filesize == 0 )
|
|
{
|
|
fclose(fp);
|
|
*lenp = 0;
|
|
//printf("loadfile null size.(%s)\n",fname);
|
|
return(0);
|
|
}
|
|
if ( filesize > buflen )
|
|
{
|
|
*allocsizep = filesize;
|
|
*bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64);
|
|
}
|
|
rewind(fp);
|
|
if ( buf == 0 )
|
|
printf("Null buf ???\n");
|
|
else
|
|
{
|
|
if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize )
|
|
printf("error reading filesize.%ld\n",(long)filesize);
|
|
buf[filesize] = 0;
|
|
}
|
|
fclose(fp);
|
|
*lenp = filesize;
|
|
//printf("loaded.(%s)\n",buf);
|
|
} //else printf("OS_loadfile couldnt load.(%s)\n",fname);
|
|
return(buf);
|
|
}
|
|
|
|
void *filestr(long *allocsizep,char *_fname)
|
|
{
|
|
long filesize = 0; char *fname,*buf = 0; void *retptr;
|
|
*allocsizep = 0;
|
|
fname = malloc(strlen(_fname)+1);
|
|
strcpy(fname,_fname);
|
|
retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep);
|
|
free(fname);
|
|
return(retptr);
|
|
}
|
|
|
|
char *send_curl(char *url,char *fname)
|
|
{
|
|
long fsize; char curlstr[1024];
|
|
sprintf(curlstr,"curl --url \"%s\" > %s",url,fname);
|
|
system(curlstr);
|
|
return(filestr(&fsize,fname));
|
|
}
|
|
|
|
cJSON *get_urljson(char *url,char *fname)
|
|
{
|
|
char *jsonstr; cJSON *json = 0;
|
|
if ( (jsonstr= send_curl(url,fname)) != 0 )
|
|
{
|
|
//printf("(%s) -> (%s)\n",url,jsonstr);
|
|
json = cJSON_Parse(jsonstr);
|
|
free(jsonstr);
|
|
}
|
|
return(json);
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
// start of dapp
|
|
//////////////////////////////////////////////
|
|
int md_unlink(char *file)
|
|
{
|
|
#ifdef _WIN32
|
|
_chmod(file, 0600);
|
|
return( _unlink(file) );
|
|
#else
|
|
return(unlink(file));
|
|
#endif
|
|
}
|
|
|
|
char *REFCOIN_CLI,DPOW_pubkeystr[67],DPOW_secpkeystr[67],DPOW_handle[67],DPOW_recvaddr[64],DPOW_recvZaddr[128];
|
|
|
|
cJSON *get_hushcli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
|
|
{
|
|
long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[32768];
|
|
sprintf(fname,"/tmp/notarizer_%s_%d",method,(rand() >> 17) % 10000);
|
|
if ( acname[0] != 0 ) {
|
|
if ( refcoin[0] != 0 && strcmp(refcoin,"HUSH3") != 0 && strcmp(refcoin,acname) != 0 )
|
|
printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname);
|
|
sprintf(cmdstr,"hush-smart-chain -ac_name=%s %s %s %s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
|
|
}
|
|
else if ( strcmp(refcoin,"HUSH3") == 0 )
|
|
sprintf(cmdstr,"hush-cli %s %s %s %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
|
|
else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 )
|
|
{
|
|
sprintf(cmdstr,"%s %s %s %s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
|
|
//printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
|
|
}
|
|
//fprintf(stderr,"system(%s)\n",cmdstr);
|
|
system(cmdstr);
|
|
*retstrp = 0;
|
|
if ( (jsonstr= filestr(&fsize,fname)) != 0 )
|
|
{
|
|
jsonstr[strlen(jsonstr)-1]='\0';
|
|
//fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr);
|
|
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
|
|
*retstrp = jsonstr;
|
|
else free(jsonstr);
|
|
md_unlink(fname);
|
|
} //else fprintf(stderr,"system(%s) -> NULL\n",cmdstr);
|
|
return(retjson);
|
|
}
|
|
|
|
cJSON *hushdex_cli(char *clistr,char **retstrp,char *method,char *arg0,char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6)
|
|
{
|
|
long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[32768];
|
|
//TODO: fix this shitty insecure jl777 fucktwattery
|
|
sprintf(fname,"/tmp/hushdex_%s_%d",method,(rand() >> 17) % 10000);
|
|
sprintf(cmdstr,"%s %s %s %s %s %s %s %s %s > %s\n",clistr,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname);
|
|
//fprintf(stderr,"system(%s)\n",cmdstr);
|
|
system(cmdstr);
|
|
*retstrp = 0;
|
|
if ( (jsonstr= filestr(&fsize,fname)) != 0 )
|
|
{
|
|
jsonstr[strlen(jsonstr)-1]='\0';
|
|
//fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr);
|
|
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
|
|
*retstrp = jsonstr;
|
|
else free(jsonstr);
|
|
md_unlink(fname);
|
|
} //else fprintf(stderr,"system(%s) -> NULL\n",cmdstr);
|
|
return(retjson);
|
|
}
|
|
|
|
bits256 hushbroadcast(char *refcoin,char *acname,cJSON *hexjson)
|
|
{
|
|
char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid;
|
|
memset(txid.bytes,0,sizeof(txid));
|
|
if ( (hexstr= jstr(hexjson,"hex")) != 0 )
|
|
{
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","","","","")) != 0 )
|
|
{
|
|
//fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
if ( strlen(retstr) >= 64 )
|
|
{
|
|
retstr[64] = 0;
|
|
decode_hex(txid.bytes,32,retstr);
|
|
}
|
|
fprintf(stderr,"broadcast %s txid.(%s)\n",strlen(acname)>0?acname:refcoin,bits256_str(str,txid));
|
|
free(retstr);
|
|
}
|
|
}
|
|
return(txid);
|
|
}
|
|
|
|
bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis,char *oprethexstr)
|
|
{
|
|
char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
|
|
memset(txid.bytes,0,sizeof(txid));
|
|
sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN);
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"false","","",oprethexstr,"")) != 0 )
|
|
{
|
|
fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
if ( strlen(retstr) >= 64 )
|
|
{
|
|
retstr[64] = 0;
|
|
decode_hex(txid.bytes,32,retstr);
|
|
}
|
|
fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid));
|
|
free(retstr);
|
|
}
|
|
return(txid);
|
|
}
|
|
|
|
bits256 tokentransfer(char *refcoin,char *acname,char *tokenid,char *destpub,int64_t units)
|
|
{
|
|
char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
|
|
memset(txid.bytes,0,sizeof(txid));
|
|
sprintf(numstr,"%llu",(long long)units);
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"tokentransfer",tokenid,destpub,numstr,"","","","")) != 0 )
|
|
{
|
|
txid = hushbroadcast(refcoin,acname,retjson);
|
|
fprintf(stderr,"tokentransfer returned (%s)\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"tokentransfer.(%s) error.(%s)\n",acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(txid);
|
|
}
|
|
|
|
char *get_tokenaddress(char *refcoin,char *acname,char *tokenaddr)
|
|
{
|
|
char *retstr,*str; cJSON *retjson;
|
|
tokenaddr[0] = 0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"tokenaddress","","","","","","","")) != 0 )
|
|
{
|
|
if ( (str= jstr(retjson,"myCCAddress(Tokens)")) != 0 )
|
|
{
|
|
strcpy(tokenaddr,str);
|
|
fprintf(stderr,"tokenaddress returned (%s)\n",tokenaddr);
|
|
free_json(retjson);
|
|
return(tokenaddr);
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
//fprintf(stderr,"tokentransfer.(%s) error.(%s)\n",acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int64_t get_tokenbalance(char *refcoin,char *acname,char *tokenid)
|
|
{
|
|
cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"tokenbalance",tokenid,"","","","","","")) != 0 )
|
|
{
|
|
amount = j64bits(retjson,"balance");
|
|
fprintf(stderr,"tokenbalance %llu\n",(long long)amount);
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
//printf("retstr %s -> %.8f\n",retstr,dstr(amount));
|
|
free(retstr);
|
|
}
|
|
return (amount);
|
|
}
|
|
|
|
cJSON *get_decodescript(char *refcoin,char *acname,char *script)
|
|
{
|
|
cJSON *retjson; char *retstr;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"decodescript",script,"","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"get_decodescript.(%s) error.(%s)\n",acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
char *get_createmultisig2(char *refcoin,char *acname,char *msigaddr,char *redeemscript,char *pubkeyA,char *pubkeyB)
|
|
{
|
|
//char para 2 '["02c3af47b51a506b08b4ededb156cb4c3f9db9e0ac7ad27b8623c08a056fdcc220", "038e61fbface549a850862f12ed99b7cbeef5c2bd2d8f1daddb34809416f0259e1"]'
|
|
cJSON *retjson; char *retstr,*str,params[256]; int32_t height=0;
|
|
msigaddr[0] = 0;
|
|
redeemscript[0] = 0;
|
|
sprintf(params,"'[\"%s\", \"%s\"]'",pubkeyA,pubkeyB);
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"createmultisig","2",params,"","","","","")) != 0 )
|
|
{
|
|
if ( (str= jstr(retjson,"address")) != 0 )
|
|
strcpy(msigaddr,str);
|
|
if ( (str= jstr(retjson,"redeemScript")) != 0 )
|
|
strcpy(redeemscript,str);
|
|
free_json(retjson);
|
|
if ( msigaddr[0] != 0 && redeemscript[0] != 0 )
|
|
return(msigaddr);
|
|
else return(0);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"%s get_createmultisig2.(%s) error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int32_t get_coinheight(char *refcoin,char *acname,bits256 *blockhashp)
|
|
{
|
|
cJSON *retjson; char *retstr; int32_t height=0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getblockchaininfo","","","","","","","")) != 0 )
|
|
{
|
|
height = jint(retjson,"blocks");
|
|
*blockhashp = jbits256(retjson,"bestblockhash");
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"%s get_coinheight.(%s) error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(height);
|
|
}
|
|
|
|
bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height)
|
|
{
|
|
cJSON *retjson; char *retstr,heightstr[32]; bits256 hash;
|
|
memset(hash.bytes,0,sizeof(hash));
|
|
sprintf(heightstr,"%d",height);
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","","","","")) != 0 )
|
|
{
|
|
fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
if ( strlen(retstr) >= 64 )
|
|
{
|
|
retstr[64] = 0;
|
|
decode_hex(hash.bytes,32,retstr);
|
|
}
|
|
free(retstr);
|
|
}
|
|
return(hash);
|
|
}
|
|
|
|
bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash,uint32_t *blocktimep)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65]; bits256 merkleroot;
|
|
memset(merkleroot.bytes,0,sizeof(merkleroot));
|
|
*blocktimep = 0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","","","","")) != 0 )
|
|
{
|
|
merkleroot = jbits256(retjson,"merkleroot");
|
|
*blocktimep = juint(retjson,"time");
|
|
//fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"%s %s get_coinmerkleroot error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(merkleroot);
|
|
}
|
|
|
|
uint32_t get_heighttime(char *refcoin,char *acname,int32_t height)
|
|
{
|
|
bits256 blockhash; uint32_t blocktime;
|
|
blockhash = get_coinblockhash(refcoin,acname,height);
|
|
get_coinmerkleroot(refcoin,acname,blockhash,&blocktime);
|
|
return(blocktime);
|
|
}
|
|
|
|
int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight)
|
|
{
|
|
int32_t height = 0; char str[65]; bits256 bhash; uint32_t blocktime;
|
|
if ( prevheight == 0 )
|
|
height = get_coinheight(refcoin,acname,&bhash) - 20;
|
|
else height = prevheight + 1;
|
|
if ( height > 0 )
|
|
{
|
|
*blockhashp = get_coinblockhash(refcoin,acname,height);
|
|
if ( bits256_nonz(*blockhashp) != 0 )
|
|
{
|
|
*merklerootp = get_coinmerkleroot(refcoin,acname,*blockhashp,&blocktime);
|
|
if ( bits256_nonz(*merklerootp) != 0 )
|
|
return(height);
|
|
}
|
|
}
|
|
memset(blockhashp,0,sizeof(*blockhashp));
|
|
memset(merklerootp,0,sizeof(*merklerootp));
|
|
return(0);
|
|
}
|
|
|
|
cJSON *get_rawmempool(char *refcoin,char *acname)
|
|
{
|
|
cJSON *retjson; char *retstr;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getrawmempool","","","","","","","")) != 0 )
|
|
{
|
|
//printf("mempool.(%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"get_rawmempool.(%s) error.(%s)\n",acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
|
|
{
|
|
cJSON *retjson; char *retstr,jsonbuf[256];
|
|
if ( refcoin[0] != 0 && strcmp(refcoin,"HUSH3") != 0 )
|
|
printf("warning: assumes %s has addressindex enabled\n",refcoin);
|
|
sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr);
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","","","","")) != 0 )
|
|
{
|
|
//printf("addressutxos.(%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65];
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"get_rawtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *get_z_viewtransaction(char *refcoin,char *acname,bits256 txid)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65];
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_viewtransaction",bits256_str(str,txid),"","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"get_z_viewtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *get_listunspent(char *refcoin,char *acname)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65];
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"listunspent","","","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"get_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *get_getinfo(char *refcoin,char *acname)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65];
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getinfo","","","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"get_getinfo.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *z_listunspent(char *refcoin,char *acname)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65];
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_listunspent","","","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"z_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *z_listoperationids(char *refcoin,char *acname)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65];
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_listoperationids","","","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"z_listoperationids.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *z_getoperationstatus(char *refcoin,char *acname,char *opid)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65],params[512];
|
|
sprintf(params,"'[\"%s\"]'",opid);
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_getoperationstatus",params,"","","","","","")) != 0 )
|
|
{
|
|
//printf("got status (%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"z_getoperationstatus.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *z_getoperationresult(char *refcoin,char *acname,char *opid)
|
|
{
|
|
cJSON *retjson; char *retstr,str[65],params[512];
|
|
sprintf(params,"'[\"%s\"]'",opid);
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_getoperationresult",params,"","","","","","")) != 0 )
|
|
{
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"z_getoperationresult.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare)
|
|
{
|
|
cJSON *retjson; char *retstr; int32_t res=0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","","","","")) != 0 )
|
|
{
|
|
if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1;
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return (res);
|
|
}
|
|
|
|
int32_t z_validateaddress(char *refcoin,char *acname,char *depositaddr, char *compare)
|
|
{
|
|
cJSON *retjson; char *retstr; int32_t res=0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_validateaddress",depositaddr,"","","","","","")) != 0 )
|
|
{
|
|
if (is_cJSON_True(jobj(retjson,compare)) != 0 )
|
|
res=1;
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"z_validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
return (res);
|
|
}
|
|
|
|
int64_t get_getbalance(char *refcoin,char *acname)
|
|
{
|
|
cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getbalance","","","","","","","")) != 0 )
|
|
{
|
|
fprintf(stderr,"get_getbalance.(%s) %s returned json!\n",refcoin,acname);
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
amount = atof(retstr) * SATOSHIDEN;
|
|
sprintf(cmpstr,"%.8f",dstr(amount));
|
|
if ( strcmp(retstr,cmpstr) != 0 )
|
|
amount++;
|
|
//printf("retstr %s -> %.8f\n",retstr,dstr(amount));
|
|
free(retstr);
|
|
}
|
|
return (amount);
|
|
}
|
|
|
|
int64_t z_getbalance(char *refcoin,char *acname,char *coinaddr)
|
|
{
|
|
cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_getbalance",coinaddr,"","","","","","")) != 0 )
|
|
{
|
|
fprintf(stderr,"z_getbalance.(%s) %s returned json!\n",refcoin,acname);
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
amount = atof(retstr) * SATOSHIDEN;
|
|
sprintf(cmpstr,"%.8f",dstr(amount));
|
|
if ( strcmp(retstr,cmpstr) != 0 )
|
|
amount++;
|
|
//printf("retstr %s -> %.8f\n",retstr,dstr(amount));
|
|
free(retstr);
|
|
}
|
|
return (amount);
|
|
}
|
|
|
|
int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr)
|
|
{
|
|
cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
|
|
privkey[0] = 0;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_exportkey",zaddr,"","","","","","")) != 0 )
|
|
{
|
|
fprintf(stderr,"z_exportkey.(%s) %s returned json!\n",refcoin,acname);
|
|
free_json(retjson);
|
|
return(-1);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
//printf("retstr %s -> %.8f\n",retstr,dstr(amount));
|
|
strcpy(privkey,retstr);
|
|
free(retstr);
|
|
return(0);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname)
|
|
{
|
|
cJSON *retjson; char *retstr; int64_t amount=0; int32_t retval = -1;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"getnewaddress","","","","","","","")) != 0 )
|
|
{
|
|
fprintf(stderr,"getnewaddress.(%s) %s returned json!\n",refcoin,acname);
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
strcpy(coinaddr,retstr);
|
|
free(retstr);
|
|
retval = 0;
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
|
|
{
|
|
cJSON *retjson; char *retstr; int64_t amount=0; int32_t retval = -1;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"z_getnewaddress",typestr,"","","","","","")) != 0 )
|
|
{
|
|
fprintf(stderr,"z_getnewaddress.(%s) %s returned json!\n",refcoin,acname);
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
strcpy(coinaddr,retstr);
|
|
free(retstr);
|
|
retval = 0;
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int64_t find_onetime_amount(char *coinstr,char *coinaddr)
|
|
{
|
|
cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0;
|
|
coinaddr[0] = 0;
|
|
if ( (array= get_listunspent(coinstr,"")) != 0 )
|
|
{
|
|
//printf("got listunspent.(%s)\n",jprint(array,0));
|
|
if ( (n= cJSON_GetArraySize(array)) > 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
if (is_cJSON_False(jobj(item, "spendable")) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
if ( (addr= jstr(item,"address")) != 0 )
|
|
{
|
|
strcpy(coinaddr,addr);
|
|
amount = z_getbalance(coinstr,"",coinaddr);
|
|
printf("found address.(%s) with amount %.8f\n",coinaddr,dstr(amount));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
free_json(array);
|
|
}
|
|
return(amount);
|
|
}
|
|
|
|
int64_t find_sprout_amount(char *coinstr,char *zcaddr)
|
|
{
|
|
cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0;
|
|
zcaddr[0] = 0;
|
|
if ( (array= z_listunspent(coinstr,"")) != 0 )
|
|
{
|
|
if ( (n= cJSON_GetArraySize(array)) > 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
if ( (addr= jstr(item,"address")) != 0 && addr[0] == 'z' && addr[1] == 'c' )
|
|
{
|
|
strcpy(zcaddr,addr);
|
|
amount = z_getbalance(coinstr,"",zcaddr);
|
|
printf("found address.(%s) with amount %.8f\n",zcaddr,dstr(amount));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
free_json(array);
|
|
}
|
|
return(amount);
|
|
}
|
|
|
|
void importaddress(char *refcoin,char *acname,char *depositaddr)
|
|
{
|
|
cJSON *retjson; char *retstr;
|
|
if ( (retjson= get_hushcli(refcoin,&retstr,acname,"importaddress",depositaddr,"","true","","","","")) != 0 )
|
|
{
|
|
printf("importaddress.(%s)\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"importaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr);
|
|
free(retstr);
|
|
}
|
|
}
|
|
|
|
int32_t z_sendmany(char *opidstr,char *coinstr,char *acname,char *srcaddr,char *destaddr,int64_t amount,char *memostr)
|
|
{
|
|
cJSON *retjson; char *retstr,params[1024],addr[128]; int32_t retval = -1;
|
|
sprintf(params,"'[{\"address\":\"%s\",\"amount\":%.8f,\"memo\":\"%s\"}]'",destaddr,dstr(amount),memostr);
|
|
sprintf(addr,"\"%s\"",srcaddr);
|
|
printf("z_sendmany.(%s %s) from.(%s) -> %s\n",coinstr,acname,srcaddr,params);
|
|
if ( (retjson= get_hushcli(coinstr,&retstr,acname,"z_sendmany",addr,params,"","","","","")) != 0 )
|
|
{
|
|
printf("unexpected json z_sendmany.(%s)\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"z_sendmany.(%s) -> opid.(%s)\n",coinstr,retstr);
|
|
strcpy(opidstr,retstr);
|
|
free(retstr);
|
|
retval = 0;
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr)
|
|
{
|
|
cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
|
|
sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
|
|
if ( (retjson= get_hushcli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","","","","")) != 0 )
|
|
{
|
|
if ( (opstr= jstr(retjson,"opid")) != 0 )
|
|
strcpy(opidstr,opstr);
|
|
retval = jint(retjson,"remainingNotes");
|
|
fprintf(stderr,"%s\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"z_mergetoaddress.(%s) -> opid.(%s)\n",coinstr,retstr);
|
|
strcpy(opidstr,retstr);
|
|
free(retstr);
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int32_t empty_mempool(char *coinstr,char *acname)
|
|
{
|
|
cJSON *array; int32_t n;
|
|
if ( (array= get_rawmempool(coinstr,acname)) != 0 )
|
|
{
|
|
if ( (n= cJSON_GetArraySize(array)) > 0 )
|
|
return(0);
|
|
free_json(array);
|
|
return(1);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required)
|
|
{
|
|
cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid;
|
|
*totalp = 0;
|
|
if ( (n= cJSON_GetArraySize(unspents)) > 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(unspents,i);
|
|
satoshis = jdouble(item,"amount") * SATOSHIDEN;
|
|
txid = jbits256(item,"txid");
|
|
v = jint(item,"vout");
|
|
if ( bits256_nonz(txid) != 0 )
|
|
{
|
|
vin = cJSON_CreateObject();
|
|
jaddbits256(vin,"txid",txid);
|
|
jaddnum(vin,"vout",v);
|
|
jaddi(vins,vin);
|
|
*totalp += satoshis;
|
|
if ( (*totalp) >= required )
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return(vins);
|
|
}
|
|
|
|
int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr)
|
|
{
|
|
cJSON *txobj,*vouts,*vout,*vins,*vin,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numarray,retval = 0, hasvout=0;
|
|
if ( (txobj= get_rawtransaction(refcoin,acname,txid)) != 0 )
|
|
{
|
|
if ( (vouts= jarray(&numarray,txobj,"vout")) != 0 )
|
|
{
|
|
for (i=0; i<numarray; i++)
|
|
{
|
|
if ((vout = jitem(vouts,i)) !=0 && (sobj= jobj(vout,"scriptPubKey")) != 0 )
|
|
{
|
|
if ( (addresses= jarray(&n,sobj,"addresses")) != 0 )
|
|
{
|
|
for (j=0; j<n; j++)
|
|
{
|
|
addr = jstri(addresses,j);
|
|
if ( strcmp(addr,coinaddr) == 0 )
|
|
{
|
|
//fprintf(stderr,"found %s in %s v%d\n",coinaddr,bits256_str(str,txid),i);
|
|
hasvout = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (hasvout==1) break;
|
|
}
|
|
}
|
|
// if (hasvout==1 && (vins=jarray(&numarray,txobj,"vin"))!=0)
|
|
// {
|
|
// for (int i=0;i<numarray;i++)
|
|
// {
|
|
// if ((vin=jitem(vins,i))!=0 && validateaddress(refcoin,acname,jstr(vin,"address"),"ismine")!=0)
|
|
// {
|
|
// retval=1;
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
free_json(txobj);
|
|
}
|
|
return(hasvout);
|
|
}
|
|
|
|
int32_t have_pending_opid(char *coinstr,int32_t clearresults)
|
|
{
|
|
cJSON *array,*status,*result; int32_t i,n,j,m,pending = 0; char *statusstr;
|
|
if ( (array= z_listoperationids(coinstr,"")) != 0 )
|
|
{
|
|
if ( (n= cJSON_GetArraySize(array)) > 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
if ( (status= z_getoperationstatus(coinstr,"",jstri(array,i))) != 0 )
|
|
{
|
|
if ( (m= cJSON_GetArraySize(status)) > 0 )
|
|
{
|
|
for (j=0; j<m; j++)
|
|
{
|
|
if ( (statusstr= jstr(jitem(status,j),"status")) != 0 )
|
|
{
|
|
if ( strcmp(statusstr,"executing") == 0 )
|
|
{
|
|
pending++;
|
|
//printf("pending.%d\n",pending);
|
|
}
|
|
else if ( clearresults != 0 )
|
|
{
|
|
if ( (result= z_getoperationresult(coinstr,"",jstri(array,i))) != 0 )
|
|
{
|
|
free_json(result);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
free_json(status);
|
|
}
|
|
}
|
|
}
|
|
free_json(array);
|
|
}
|
|
return(pending);
|
|
}
|
|
|
|
int64_t utxo_value(char *refcoin,char *srcaddr,bits256 txid,int32_t v)
|
|
{
|
|
cJSON *txjson,*vouts,*vout,*sobj,*array; int32_t numvouts,numaddrs; int64_t val,value = 0; char *addr,str[65];
|
|
srcaddr[0] = 0;
|
|
if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 )
|
|
{
|
|
if ( (vouts= jarray(&numvouts,txjson,"vout")) != 0 && v < numvouts )
|
|
{
|
|
vout = jitem(vouts,v);
|
|
if ( (val= jdouble(vout,"value")*SATOSHIDEN) != 0 && (sobj= jobj(vout,"scriptPubKey")) != 0 )
|
|
{
|
|
if ( (array= jarray(&numaddrs,sobj,"addresses")) != 0 && numaddrs == 1 && (addr= jstri(array,0)) != 0 && strlen(addr) < 64 )
|
|
{
|
|
strcpy(srcaddr,addr);
|
|
value = val;
|
|
} else printf("couldnt get unique address for %s/%d\n",bits256_str(str,txid),v);
|
|
} else printf("error getting value for %s/v%d\n",bits256_str(str,txid),v);
|
|
}
|
|
}
|
|
return(value);
|
|
}
|
|
|
|
int32_t verify_vin(char *refcoin,bits256 txid,int32_t v,char *cmpaddr)
|
|
{
|
|
cJSON *txjson,*vins,*vin; int32_t numvins; char vinaddr[64],str[65];
|
|
vinaddr[0] = 0;
|
|
if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 )
|
|
{
|
|
if ( (vins= jarray(&numvins,txjson,"vin")) != 0 && v < numvins )
|
|
{
|
|
vin = jitem(vins,v);
|
|
if ( utxo_value(refcoin,vinaddr,jbits256(vin,"txid"),jint(vin,"vout")) > 0 && strcmp(vinaddr,cmpaddr) == 0 )
|
|
return(0);
|
|
printf("mismatched vinaddr.(%s) vs %s\n",vinaddr,cmpaddr);
|
|
}
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
int32_t txid_in_vins(char *refcoin,bits256 txid,bits256 cmptxid)
|
|
{
|
|
cJSON *txjson,*vins,*vin; int32_t numvins,v,vinvout; bits256 vintxid; char str[65];
|
|
if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 )
|
|
{
|
|
if ( (vins= jarray(&numvins,txjson,"vin")) != 0 )
|
|
{
|
|
for (v=0; v<numvins; v++)
|
|
{
|
|
vin = jitem(vins,v);
|
|
vintxid = jbits256(vin,"txid");
|
|
vinvout = jint(vin,"vout");
|
|
if ( memcmp(&vintxid,&cmptxid,sizeof(vintxid)) == 0 && vinvout == 0 )
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
int32_t dpow_pubkey()
|
|
{
|
|
char *pstr,*retstr,*str; cJSON *retjson; int32_t retval = -1;
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_stats","","","","","","","")) != 0 )
|
|
{
|
|
if ( (pstr= jstr(retjson,"publishable_pubkey")) != 0 && strlen(pstr) == 66 )
|
|
{
|
|
strcpy(DPOW_pubkeystr,pstr);
|
|
if ( (str= jstr(retjson,"secpkey")) != 0 )
|
|
strcpy(DPOW_secpkeystr,str);
|
|
if ( (str= jstr(retjson,"handle")) != 0 )
|
|
strcpy(DPOW_handle,str);
|
|
if ( (str= jstr(retjson,"recvaddr")) != 0 )
|
|
strcpy(DPOW_recvaddr,str);
|
|
if ( (str= jstr(retjson,"recvZaddr")) != 0 )
|
|
strcpy(DPOW_recvZaddr,str);
|
|
retval = 0;
|
|
}
|
|
if ( retval != 0 )
|
|
printf("DEX_stats.(%s)\n",jprint(retjson,0));
|
|
free_json(retjson);
|
|
}
|
|
if ( DPOW_secpkeystr[0] == 0 )
|
|
strcpy(DPOW_secpkeystr,"02deaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead");
|
|
return(retval);
|
|
}
|
|
|
|
cJSON *dpow_get(uint32_t shorthash)
|
|
{
|
|
cJSON *retjson; char *retstr,numstr[32];
|
|
sprintf(numstr,"%u",shorthash);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_get",numstr,"","","","","","")) != 0 )
|
|
{
|
|
//printf("DEX_get.(%s)\n",jprint(retjson,0));
|
|
if ( juint(retjson,"cancelled") != 0 )
|
|
{
|
|
free_json(retjson);
|
|
retjson = 0;
|
|
}
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"dpow_get.(%u) error.(%s)\n",shorthash,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *dpow_cancel(uint32_t shorthash)
|
|
{
|
|
cJSON *retjson; char *retstr,numstr[32];
|
|
sprintf(numstr,"%u",shorthash);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_cancel",numstr,"","","","","","")) != 0 )
|
|
{
|
|
//printf("DEX_cancel.(%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"dpow_cancel.(%u) error.(%s)\n",shorthash,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *dpow_notarize(char *coin,int32_t height)
|
|
{
|
|
cJSON *retjson; char *retstr,numstr[32];
|
|
sprintf(numstr,"%u",height);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_notarize",coin,numstr,"","","","","")) != 0 )
|
|
{
|
|
//printf("DEX_notarize.(%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"dpow_notarize.(%s.%d) error.(%s)\n",coin,height,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *dpow_broadcast(int32_t priority,char *hexstr,char *tagA,char *tagB,char *pubkey,char *volA,char *volB)
|
|
{
|
|
cJSON *retjson; char *retstr,numstr[32];
|
|
sprintf(numstr,"%u",priority);
|
|
//fprintf(stderr,"broadcast (%s) (%s) (%s) (%s) (%s) [%s %s]\n",hexstr,numstr,tagA,tagB,pubkey,volA,volB);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_broadcast",hexstr,numstr,tagA,tagB,pubkey,volA,volB)) != 0 )
|
|
{
|
|
//fprintf(stderr,"DEX_broadcast.(%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"dpow_broadcast.(%s/%s) [%s %s] %s error.(%s)\n",tagA,tagB,volA,volB,hexstr,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *dpow_publish(int32_t priority,char *filename)
|
|
{
|
|
cJSON *retjson; char *retstr,numstr[32];
|
|
sprintf(numstr,"%u",priority);
|
|
//fprintf(stderr,"broadcast (%s) (%s) (%s) (%s) (%s) [%s %s]\n",hexstr,numstr,tagA,tagB,pubkey,volA,volB);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_publish",filename,numstr,"0","","","","")) != 0 )
|
|
{
|
|
//fprintf(stderr,"DEX_broadcast.(%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"dpow_publish.(%s) %d error.(%s)\n",filename,priority,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *dpow_subscribe(int32_t priority,char *filename,char *publisher)
|
|
{
|
|
cJSON *retjson; char *retstr,numstr[32];
|
|
sprintf(numstr,"%u",priority);
|
|
//fprintf(stderr,"broadcast (%s) (%s) (%s) (%s) (%s) [%s %s]\n",hexstr,numstr,tagA,tagB,pubkey,volA,volB);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_subscribe",filename,numstr,"0",publisher,"","","")) != 0 )
|
|
{
|
|
//fprintf(stderr,"DEX_broadcast.(%s)\n",jprint(retjson,0));
|
|
return(retjson);
|
|
}
|
|
else if ( retstr != 0 )
|
|
{
|
|
fprintf(stderr,"dpow_subscribe.(%s) %d error.(%s)\n",filename,priority,retstr);
|
|
free(retstr);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
cJSON *dpow_ntzdata(char *coin,int32_t priority,int32_t height,bits256 blockhash)
|
|
{
|
|
char hexstr[256],heightstr[32];
|
|
bits256_str(hexstr,blockhash);
|
|
sprintf(heightstr,"%u",height);
|
|
return(dpow_broadcast(priority,hexstr,coin,heightstr,DPOW_pubkeystr,"",""));
|
|
}
|
|
|
|
bits256 dpow_ntzhash(char *coin,int32_t *prevntzheightp,uint32_t *prevntztimep)
|
|
{
|
|
char *pstr,*retstr; cJSON *retjson,*array,*item; int32_t n; bits256 ntzhash; uint8_t buf[4];
|
|
memset(&ntzhash,0,sizeof(ntzhash));
|
|
*prevntzheightp = 0;
|
|
*prevntztimep = 0;
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",coin,"notarizations",DPOW_pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 )
|
|
{
|
|
item = jitem(array,0);
|
|
if ( (pstr= jstr(item,"decrypted")) != 0 && strlen(pstr) == 2*(32 + 2*4) )
|
|
{
|
|
decode_hex(ntzhash.bytes,32,pstr);
|
|
decode_hex(buf,4,pstr + 32*2);
|
|
*prevntzheightp = ((int32_t)buf[3] + ((int32_t)buf[2] << 8) + ((int32_t)buf[1] << 16) + ((int32_t)buf[0] << 24));
|
|
decode_hex(buf,4,pstr + 32*2+8);
|
|
*prevntztimep = ((int32_t)buf[3] + ((int32_t)buf[2] << 8) + ((int32_t)buf[1] << 16) + ((int32_t)buf[0] << 24));
|
|
//char str[65]; fprintf(stderr,"%s prevntz height.%d %s\n",coin,*prevntzheightp,bits256_str(str,ntzhash));
|
|
}
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
return(ntzhash);
|
|
}
|
|
|
|
int32_t dpow_getmessage(char *payload,int32_t maxsize,char *tagA,char *tagB,char *pubkeystr)
|
|
{
|
|
cJSON *retjson,*item,*array; char *retstr,*pstr; int32_t i,n,retval = 0;
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",tagA,tagB,pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
if ( (pstr= jstr(item,"decrypted")) != 0 && strlen(pstr) < maxsize )
|
|
{
|
|
retval = 1;
|
|
strcpy(payload,pstr);
|
|
break;
|
|
}
|
|
}
|
|
//fprintf(stderr,"getmessage(%s, %s, %s) -> n.%d retval.%d\n",tagA,tagB,pubkeystr,n,retval);
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int32_t dpow_hasmessage(char *payload,char *tagA,char *tagB,char *pubkeystr)
|
|
{
|
|
cJSON *retjson,*item,*array; char *retstr,*pstr; int32_t i,n,retval = 0;
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",tagA,tagB,pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 )
|
|
{
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
if ( (pstr= jstr(item,"decrypted")) != 0 && strcmp(payload,pstr) == 0 )
|
|
{
|
|
retval = 1;
|
|
//fprintf(stderr,"already have %s/%s/%s\n",tagA,tagB,pubkeystr);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
int32_t dpow_pubkeyregister(int32_t priority)
|
|
{
|
|
cJSON *retjson,*array,*item; char *retstr,*pstr=0; int32_t i,n=0,len;
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",(char *)"handles",DPOW_handle,DPOW_pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 )
|
|
{
|
|
item = jitem(array,0);
|
|
if ( (pstr= jstr(item,"decrypted")) != 0 )
|
|
{
|
|
//fprintf(stderr,"found secpkey.(%s)\n",pstr);
|
|
}
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
if ( pstr == 0 )
|
|
{
|
|
dpow_broadcast(priority,DPOW_secpkeystr,(char *)"handles",DPOW_handle,DPOW_pubkeystr,"","");
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int32_t dpow_tokenregister(char *existing,int32_t priority,char *token_name,char *tokenid)
|
|
{
|
|
cJSON *retjson,*array,*item; char *retstr,*pstr=0; int32_t i,n=0,len;
|
|
existing[0] = 0;
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",(char *)"tokens",token_name,DPOW_pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 )
|
|
{
|
|
item = jitem(array,0);
|
|
if ( juint(item,"cancelled") == 0 && (pstr= jstr(item,"decrypted")) != 0 )
|
|
{
|
|
strcpy(existing,pstr);
|
|
if ( tokenid != 0 && strcmp(pstr,tokenid) != 0 )
|
|
{
|
|
fprintf(stderr,"found %s.tokenid (%s) != %s\n",token_name,pstr,tokenid);
|
|
pstr = 0;
|
|
}
|
|
}
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
if ( pstr == 0 && tokenid != 0 )
|
|
{
|
|
fprintf(stderr,"broadcast tokens %s/%s\n",token_name,tokenid);
|
|
dpow_broadcast(priority,tokenid,(char *)"tokens",token_name,DPOW_pubkeystr,"","");
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/*bits256 hush_DEX_filehash(FILE *fp,uint64_t offset0,uint64_t rlen,char *fname)
|
|
{
|
|
bits256 filehash; uint8_t *data = (uint8_t *)calloc(1,rlen);
|
|
fseek(fp,offset0,SEEK_SET);
|
|
memset(filehash.bytes,0,sizeof(filehash));
|
|
if ( fread(data,1,rlen,fp) == rlen )
|
|
vcalc_sha256(0,filehash.bytes,data,rlen);
|
|
else fprintf(stderr," reading %lld bytes from %s.%llu\n",(long long)rlen,fname,(long long)offset0);
|
|
free(data);
|
|
return(filehash);
|
|
}*/
|
|
|
|
int32_t dpow_fileregister(char *existing,int32_t priority,char *fname,char *coin,int64_t price)
|
|
{
|
|
FILE *fp; cJSON *retjson,*array,*item; bits256 existinghash,filehash; char tagA[16],pricestr[32],str[65],*retstr,*pstr=0; int32_t i,n=0,len;
|
|
existing[0] = 0;
|
|
sprintf(pricestr,"%.8f",dstr(price));
|
|
//fprintf(stderr,"filereg (%s) (%s) (%s)\n",fname,coin,pricestr);
|
|
memset(&filehash,0,sizeof(filehash));
|
|
if ( (fp= fopen(fname,"rb")) != 0 ) // better to use hash of file
|
|
{
|
|
fseek(fp,0,SEEK_END);
|
|
filehash.ulongs[0] = (uint64_t)ftell(fp);
|
|
fclose(fp);
|
|
} else return(-1);
|
|
sprintf(tagA,"'#%s'",fname);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",tagA,coin,DPOW_pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 )
|
|
{
|
|
item = jitem(array,0);
|
|
if ( juint(item,"cancelled") == 0 && (pstr= jstr(item,"decrypted")) != 0 )
|
|
{
|
|
strcpy(existing,pstr);
|
|
if ( is_hexstr(existing,0) == sizeof(existinghash)*2 )
|
|
{
|
|
decode_hex(existinghash.bytes,sizeof(existinghash),existing);
|
|
if ( memcmp(&filehash,&existinghash,sizeof(filehash)) != 0 )
|
|
{
|
|
fprintf(stderr,"found mismatched %s vs %s: %s (%s %s)\n",existing,bits256_str(str,filehash),fname,coin,pricestr);
|
|
pstr = 0;
|
|
} //else fprintf(stderr,"found matching %s\n",jprint(item,0));
|
|
}
|
|
}
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
if ( pstr == 0 )
|
|
{
|
|
fprintf(stderr,"broadcast %s %s (%s %s)\n",bits256_str(str,filehash),fname,coin,pricestr);
|
|
dpow_broadcast(priority,bits256_str(str,filehash),tagA,coin,DPOW_pubkeystr,"1",pricestr);
|
|
return(1);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
bits256 dpow_blockhash(char *coin,int32_t height)
|
|
{
|
|
cJSON *retjson,*array,*item; char *retstr,*pstr=0,numstr[32]; int32_t i,n=0,len; bits256 hash;
|
|
memset(hash.bytes,0,sizeof(hash));
|
|
sprintf(numstr,"%d",height);
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",coin,numstr,DPOW_pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 )
|
|
{
|
|
item = jitem(array,0);
|
|
if ( (pstr= jstr(item,"decrypted")) != 0 )
|
|
{
|
|
//fprintf(stderr,"found blockhash.(%s)\n",pstr);
|
|
if ( strlen(pstr) == 64 )
|
|
decode_hex(hash.bytes,sizeof(hash),pstr);
|
|
}
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
return(hash);
|
|
}
|
|
|
|
struct inboxinfo
|
|
{
|
|
uint32_t shorthash;
|
|
char *jsonstr,senderpub[67];
|
|
};
|
|
|
|
struct inboxinfo **dpow_inboxcheck(int32_t *nump,uint32_t *stopatp,char *tagB)
|
|
{
|
|
cJSON *retjson,*array,*item; struct inboxinfo **ptrs=0; char *senderpub,*retstr,*ptr,*pstr=0,stopstr[32]; int32_t i,j,n,m=0,len;
|
|
sprintf(stopstr,"%u",*stopatp);
|
|
*nump = 0;
|
|
if ( (retjson= get_hushcli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list",stopstr,"0",(char *)"inbox",tagB,DPOW_pubkeystr,"","")) != 0 )
|
|
{
|
|
if ( (array= jarray(&n,retjson,"matches")) != 0 && n > 0 )
|
|
{
|
|
ptrs = calloc(n,sizeof(*ptrs));
|
|
for (i=0; i<n; i++)
|
|
{
|
|
item = jitem(array,i);
|
|
if ( (senderpub= jstr(item,"senderpub")) != 0 && is_hexstr(senderpub,0) == 66 )
|
|
{
|
|
if ( m == 0 )
|
|
*stopatp = juint(item,"id");
|
|
if ( (pstr= jstr(item,"decrypted")) != 0 )
|
|
{
|
|
ptr = clonestr(pstr);
|
|
for (j=0; ptr[j]!=0; j++)
|
|
if ( ptr[j] == '\'' )
|
|
ptr[j] = '"';
|
|
ptrs[m] = calloc(1,sizeof(struct inboxinfo));
|
|
ptrs[m]->shorthash = juint(item,"id");
|
|
ptrs[m]->jsonstr = ptr;
|
|
strcpy(ptrs[m]->senderpub,senderpub);
|
|
m++;
|
|
}
|
|
}
|
|
}
|
|
*nump = m;
|
|
}
|
|
free_json(retjson);
|
|
}
|
|
return(ptrs);
|
|
}
|
|
|