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.

1497 lines
62 KiB

9 years ago
/******************************************************************************
* Copyright © 2014-2015 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. *
* *
******************************************************************************/
#ifndef xcode_subatomic_h
#define xcode_subatomic_h
//https://bitcointalk.org/index.php?topic=1172153.0
#include <stdbool.h>
struct bp_key { void *k; };
typedef struct cstring {
char *str; // string data, incl. NUL
size_t len; // length of string, not including NUL
size_t alloc; // total allocated buffer length
} cstring;
extern bool bp_key_init(struct bp_key *key);
extern void bp_key_free(struct bp_key *key);
extern bool bp_key_generate(struct bp_key *key);
extern bool bp_privkey_set(struct bp_key *key, const void *privkey, size_t pk_len);
extern bool bp_pubkey_set(struct bp_key *key, const void *pubkey, size_t pk_len);
extern bool bp_key_secret_set(struct bp_key *key, const void *privkey_, size_t pk_len);
extern bool bp_privkey_get(const struct bp_key *key, void **privkey, size_t *pk_len);
extern bool bp_pubkey_get(const struct bp_key *key, void **pubkey, size_t *pk_len);
extern bool bp_key_secret_get(void *p, size_t len, const struct bp_key *key);
extern bool bp_sign(const struct bp_key *key, const void *data, size_t data_len,void **sig_, size_t *sig_len_);
extern bool bp_verify(const struct bp_key *key, const void *data, size_t data_len,const void *sig, size_t sig_len);
void cstr_free(cstring *s, bool free_buf);
cstring *base58_encode_check(unsigned char addrtype,bool have_addrtype,const void *data,size_t data_len);
cstring *base58_decode_check(unsigned char *addrtype, const char *s_in);
int32_t btc_setprivkey(struct bp_key *key,char *privkeystr);
int32_t btc_getpubkey(char pubkeystr[67],uint8_t pubkeybuf[33],struct bp_key *key);
void btc_freekey(void *key);
struct btcaddr
{
struct bp_key key;
uint8_t *pubkey; uint16_t p2sh;
char addr[36],coin[8];
uint8_t privkey[280];
};
#define SCRIPT_OP_IF 0x63
#define SCRIPT_OP_ELSE 0x67
#define SCRIPT_OP_DUP 0x76
#define SCRIPT_OP_ENDIF 0x68
#define SCRIPT_OP_TRUE 0x51
#define SCRIPT_OP_2 0x52
#define SCRIPT_OP_3 0x53
#define SCRIPT_OP_EQUALVERIFY 0x88
#define SCRIPT_OP_HASH160 0xa9
#define SCRIPT_OP_EQUAL 0x87
#define SCRIPT_OP_CHECKSIG 0xac
#define SCRIPT_OP_CHECKMULTISIG 0xae
#define SCRIPT_OP_CHECKMULTISIGVERIFY 0xaf
char *create_atomictx_scripts(uint8_t addrtype,char *scriptPubKey,char *p2shaddr,char *pubkeyA,char *pubkeyB,char *hash160str)
{
// if ( refund ) OP_HASH160 <2of2 multisig hash> OP_EQUAL // standard multisig
// else OP_DUP OP_HASH160 <hash160> OP_EQUALVERIFY OP_CHECKSIG // standard spend
cstring *btc_addr; char *retstr; uint8_t pubkeyAbytes[33],pubkeyBbytes[33],hash160[20],tmpbuf[24],hex[4096]; int32_t i,n = 0;
decode_hex(pubkeyAbytes,33,pubkeyA);
decode_hex(pubkeyBbytes,33,pubkeyB);
decode_hex(hash160,20,hash160str);
hex[n++] = SCRIPT_OP_IF;
hex[n++] = SCRIPT_OP_2;
hex[n++] = 33, memcpy(&hex[n],pubkeyAbytes,33), n += 33;
hex[n++] = 33, memcpy(&hex[n],pubkeyBbytes,33), n += 33;
hex[n++] = SCRIPT_OP_2;
hex[n++] = SCRIPT_OP_CHECKMULTISIG;
hex[n++] = SCRIPT_OP_ELSE;
hex[n++] = SCRIPT_OP_DUP;
hex[n++] = SCRIPT_OP_HASH160;
hex[n++] = 20; memcpy(&hex[n],hash160,20); n += 20;
hex[n++] = SCRIPT_OP_EQUALVERIFY;
hex[n++] = SCRIPT_OP_CHECKSIG;
hex[n++] = SCRIPT_OP_ENDIF;
if ( (retstr= calloc(1,n*2+16)) == 0 )
return(0);
//printf("pubkeyA.(%s) pubkeyB.(%s) hash160.(%s) ->\n",pubkeyA,pubkeyB,hash160str);
//strcpy(retstr,"01");
//sprintf(retstr+2,"%02x",n);
for (i=0; i<n; i++)
{
retstr[i*2] = hexbyte((hex[i]>>4) & 0xf);
retstr[i*2 + 1] = hexbyte(hex[i] & 0xf);
//printf("%02x",hex[i]);
}
retstr[n*2] = 0;
calc_OP_HASH160(scriptPubKey,tmpbuf+2,retstr);
tmpbuf[0] = SCRIPT_OP_HASH160;
tmpbuf[1] = 20;
tmpbuf[22] = SCRIPT_OP_EQUAL;
init_hexbytes_noT(scriptPubKey,tmpbuf,23);
if ( p2shaddr != 0 )
{
p2shaddr[0] = 0;
if ( (btc_addr= base58_encode_check(addrtype,true,tmpbuf+2,20)) != 0 )
{
if ( strlen(btc_addr->str) < 36 )
strcpy(p2shaddr,btc_addr->str);
cstr_free(btc_addr,true);
}
}
return(retstr);
}
#ifdef noiguana
int32_t create_MofN(uint8_t addrtype,char *redeemScript,char *scriptPubKey,char *p2shaddr,char *pubkeys[],int32_t M,int32_t N)
{
cstring *btc_addr; uint8_t pubkey[33],tmpbuf[24],hex[4096]; int32_t i,n = 0;
hex[n++] = 0x50 + M;
for (i=0; i<N; i++)
{
decode_hex(pubkey,33,pubkeys[i]);
hex[n++] = 33;
memcpy(&hex[n],pubkey,33);
n += 33;
}
hex[n++] = 0x50 + N;
hex[n++] = SCRIPT_OP_CHECKMULTISIG;
for (i=0; i<n; i++)
{
redeemScript[i*2] = hexbyte((hex[i]>>4) & 0xf);
redeemScript[i*2 + 1] = hexbyte(hex[i] & 0xf);
//fprintf(stderr,"%02x",hex[i]);
}
//fprintf(stderr," n.%d\n",n);
redeemScript[n*2] = 0;
calc_OP_HASH160(0,tmpbuf+2,redeemScript);
//printf("op160.(%s)\n",redeemScript);
tmpbuf[0] = SCRIPT_OP_HASH160;
tmpbuf[1] = 20;
tmpbuf[22] = SCRIPT_OP_EQUAL;
init_hexbytes_noT(scriptPubKey,tmpbuf,23);
p2shaddr[0] = 0;
if ( (btc_addr= base58_encode_check(addrtype,true,tmpbuf+2,20)) != 0 )
{
if ( strlen(btc_addr->str) < 36 )
strcpy(p2shaddr,btc_addr->str);
cstr_free(btc_addr,true);
}
return(n);
}
struct btcaddr *btcaddr_new(char *coinstr,char *p2sh_script)
{
uint8_t script[8192],md160[20]; char pubkeystr[512],privkeystr[512],hashstr[41]; struct coin777 *coin;
void *privkey=0,*pubkey=0; int32_t n; size_t len,slen; cstring *btc_addr; struct btcaddr *btc;
if ( (btc= calloc(1,sizeof(*btc))) == 0 || (coin = coin777_find(coinstr,1)) == 0 )
{
if ( btc != 0 )
free(btc);
return(0);
}
strncpy(btc->coin,coin->name,sizeof(btc->coin)-1);
if ( p2sh_script != 0 )
{
calc_OP_HASH160(0,md160,p2sh_script);
btc->p2sh = n = (int32_t)strlen(p2sh_script) >> 1;
decode_hex(script,n,p2sh_script);
if ( (btc_addr= base58_encode_check(coin->p2shtype,true,md160,sizeof(md160))) != 0 )
{
if ( n > sizeof(btc->privkey)-23 )
{
printf("script.(%s) len.%d is too big\n",p2sh_script,n);
free(btc);
return(0);
}
strcpy(btc->addr,btc_addr->str);
memcpy(btc->privkey,script,n);
btc->pubkey = &btc->privkey[sizeof(btc->privkey) - 23];
btc->pubkey[0] = SCRIPT_OP_HASH160;
btc->pubkey[2] = 20;
memcpy(&btc->pubkey[2],md160,20);
btc->pubkey[22] = SCRIPT_OP_EQUAL;
init_hexbytes_noT(privkeystr,script,n);
printf("type.%u btcaddr.%ld addr.(%s) %ld p2sh.(%s) %d\n",coin->p2shtype,(long)sizeof(struct btcaddr),btc->addr,(long)strlen(btc->addr),privkeystr,n);
cstr_free(btc_addr,true);
} else free(btc), btc = 0;
return(btc);
}
else if ( bp_key_init(&btc->key) != 0 && bp_key_generate(&btc->key) != 0 && bp_pubkey_get(&btc->key,&pubkey,&len) != 0 && bp_privkey_get(&btc->key,&privkey,&slen) != 0 )
{
if ( len == 33 && slen == 214 && memcmp((void *)((long)privkey + slen - 33),pubkey,33) == 0 )
{
init_hexbytes_noT(pubkeystr,pubkey,len);
init_hexbytes_noT(privkeystr,privkey,slen);
calc_OP_HASH160(hashstr,md160,pubkeystr);
if ( (btc_addr= base58_encode_check(coin->addrtype,true,md160,sizeof(md160))) != 0 )
{
strcpy(btc->addr,btc_addr->str);
memcpy(btc->privkey,privkey,slen);
btc->pubkey = &btc->privkey[slen - len];
printf("type.%u btcaddr.%ld rmd160.(%s) addr.(%s) %ld pubkey.(%s) %d privkey.(%s) %d\n",coin->addrtype,(long)sizeof(struct btcaddr),hashstr,btc->addr,(long)strlen(btc->addr),pubkeystr,(int32_t)len,privkeystr,(int32_t)slen);
cstr_free(btc_addr,true);
}
else free(btc), btc = 0;
} else free(btc), btc = 0;
}
return(btc);
}
int32_t btc_getpubkey(char pubkeystr[67],uint8_t pubkeybuf[33],struct bp_key *key)
{
void *pubkey = 0; size_t len = 0;
bp_pubkey_get(key,&pubkey,&len);
if ( pubkey != 0 )
{
if ( pubkeystr != 0 )
{
if ( len < 34 )
{
init_hexbytes_noT(pubkeystr,pubkey,(int32_t)len);
memcpy(pubkeybuf,pubkey,len);
}
else printf("btc_getpubkey error len.%d\n",(int32_t)len), len = -1;
}
//printf("btc_getpubkey len.%ld (%s).%p\n",len,pubkeystr,pubkeystr);
} else len = -1;
return((int32_t)len);
}
int32_t btc_convrmd160(char *coinaddr,uint8_t addrtype,uint8_t md160[20])
{
cstring *btc_addr;
if ( (btc_addr= base58_encode_check(addrtype,true,md160,20)) != 0 )
{
strcpy(coinaddr,btc_addr->str);
cstr_free(btc_addr,true);
return(0);
}
return(-1);
}
int32_t btc_coinaddr(char *coinaddr,uint8_t addrtype,char *pubkeystr)
{
uint8_t rmd160[20]; char hashstr[41];
calc_OP_HASH160(hashstr,rmd160,pubkeystr);
return(btc_convrmd160(coinaddr,addrtype,rmd160));
}
int32_t btc_convaddr(char *hexaddr,char *addr58)
{
uint8_t addrtype; cstring *cstr;
if ( (cstr= base58_decode_check(&addrtype,(const char *)addr58)) != 0 )
{
sprintf(hexaddr,"%02x",addrtype);
init_hexbytes_noT(hexaddr+2,(void *)cstr->str,cstr->len);
cstr_free(cstr,true);
return(0);
}
return(-1);
}
int32_t btc_priv2wip(char *wipstr,uint8_t privkey[32],uint8_t addrtype)
{
uint8_t tmp[128]; char hexstr[67]; cstring *btc_addr;
memcpy(tmp,privkey,32);
tmp[32] = 1;
init_hexbytes_noT(hexstr,tmp,32);
if ( (btc_addr= base58_encode_check(addrtype,true,tmp,33)) != 0 )
{
strcpy(wipstr,btc_addr->str);
cstr_free(btc_addr,true);
}
printf("-> (%s) -> wip.(%s) addrtype.%02x\n",hexstr,wipstr,addrtype);
return(0);
}
int32_t btc_wip2priv(uint8_t privkey[32],char *wipstr)
{
uint8_t addrtype; cstring *cstr; int32_t len = -1;
if ( (cstr= base58_decode_check(&addrtype,(const char *)wipstr)) != 0 )
{
init_hexbytes_noT((void *)privkey,(void *)cstr->str,cstr->len);
if ( cstr->str[cstr->len-1] == 0x01 )
cstr->len--;
memcpy(privkey,cstr->str,cstr->len);
len = (int32_t)cstr->len;
char tmp[138];
btc_priv2wip(tmp,privkey,addrtype);
printf("addrtype.%02x wipstr.(%llx) len.%d\n",addrtype,*(long long *)privkey,len);
cstr_free(cstr,true);
}
return(len);
}
int32_t btc_setprivkey(struct bp_key *key,char *privkeystr)
{
uint8_t privkey[512]; int32_t len = btc_wip2priv(privkey,privkeystr);
if ( len < 0 || bp_key_init(key) == 0 || bp_key_secret_set(key,privkey,len) == 0 )
{
printf("error setting privkey\n");
return(-1);
}
return(0);
}
void jumblr_freekey(void *key)
{
bp_key_free(key);
free(key);
}
int32_t btc_priv2pub(uint8_t pubkey[33],uint8_t privkey[32])
{
size_t len; void *pub = 0; int32_t retval = -1;
struct bp_key *key = calloc(1,sizeof(*key));
if ( key != 0 && bp_key_init(key) != 0 && bp_key_secret_set(key,privkey,32) != 0 )
{
bp_pubkey_get(key,&pub,&len);
bp_key_free(key);
if ( len == 33 )
memcpy(pubkey,pub,33);
if ( pub != 0 )
free(pub);
return(retval);
}
if ( key != 0 )
bp_key_free(key);
return(retval);
}
int32_t btc_pub2rmd(uint8_t rmd160[20],uint8_t pubkey[33])
{
char pubkeystr[67],hashstr[41];
init_hexbytes_noT(pubkeystr,pubkey,33);
calc_OP_HASH160(hashstr,rmd160,pubkeystr);
return(0);
}
void *jumblr_bpkey(char *pubP,struct coin777 *coin,char *coinaddr)
{
uint8_t buf[2048]; char *privkey; struct bp_key *key = 0;
//printf("coin.%s (%s)\n",coin->name,coinaddr);
if ( (privkey = dumpprivkey(coin->name,coin->serverport,coin->userpass,coinaddr)) != 0 )
{
//printf("privkey.(%s)\n",privkey);
key = calloc(1,sizeof(*key));
if ( key != 0 && btc_setprivkey(key,privkey) == 0 && btc_getpubkey(pubP,buf,key) > 0 )
return(key);
btc_freekey(key);
}
return(0);
}
void set_spendscript(char *spendscript,char *coinaddr)
{
char hexaddr[128];
btc_convaddr(hexaddr,coinaddr);
sprintf(spendscript,"76a914%s88ac",hexaddr+2);
}
int32_t script_coinaddr(char *coinaddr,cJSON *scriptobj)
{
struct destbuf buf; cJSON *addresses;
coinaddr[0] = 0;
if ( scriptobj == 0 )
return(-1);
if ( (addresses= cJSON_GetObjectItem(scriptobj,"addresses")) != 0 )
{
copy_cJSON(&buf,jitem(addresses,0));
strcpy(coinaddr,buf.buf);
return(0);
}
return(-1);
}
char *pangea_signp2sh(int32_t oldtx_format,struct cointx_info *refT,int32_t redeemi,char *redeemscript,char sigs[][256],int32_t n,uint8_t privkey[32],int32_t privkeyind)
{
char hexstr[16384]; bits256 hash2; uint8_t data[4096],sigbuf[512]; struct bp_key key;
struct cointx_info *T; int32_t i,len; void *sig = NULL; size_t siglen = 0; struct cointx_input *vin;
if ( bp_key_init(&key) != 0 && bp_key_secret_set(&key,privkey,32) != 0 )
{
if ( (T= calloc(1,sizeof(*T))) == 0 )
return(0);
*T = *refT; vin = &T->inputs[redeemi];
for (i=0; i<T->numinputs; i++)
strcpy(T->inputs[i].sigs,"00");
strcpy(vin->sigs,redeemscript);
vin->sequence = (uint32_t)-1;
T->nlocktime = 0;
//disp_cointx(&T);
emit_cointx(&hash2,data,sizeof(data),T,oldtx_format,SIGHASH_ALL);
//printf("HASH2.(%llx)\n",(long long)hash2.txid);
if ( bp_sign(&key,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 )
{
memcpy(sigbuf,sig,siglen);
sigbuf[siglen++] = SIGHASH_ALL;
init_hexbytes_noT(sigs[privkeyind],sigbuf,(int32_t)siglen);
strcpy(vin->sigs,"00");
for (i=0; i<n; i++)
{
if ( sigs[i][0] != 0 )
{
sprintf(vin->sigs + strlen(vin->sigs),"%02x%s",(int32_t)strlen(sigs[i])>>1,sigs[i]);
//printf("(%s).%ld ",sigs[i],strlen(sigs[i]));
}
}
len = (int32_t)(strlen(redeemscript)/2);
if ( len >= 0xfd )
sprintf(&vin->sigs[strlen(vin->sigs)],"4d%02x%02x",len & 0xff,(len >> 8) & 0xff);
else sprintf(&vin->sigs[strlen(vin->sigs)],"4c%02x",len);
sprintf(&vin->sigs[strlen(vin->sigs)],"%s",redeemscript);
//printf("after A.(%s) othersig.(%s) siglen.%02lx -> (%s)\n",hexstr,othersig != 0 ? othersig : "",siglen,vin->sigs);
//printf("vinsigs.(%s) %ld\n",vin->sigs,strlen(vin->sigs));
_emit_cointx(hexstr,sizeof(hexstr),T,oldtx_format);
//disp_cointx(&T);
free(T);
return(clonestr(hexstr));
}
else printf("error signing\n");
free(T);
}
return(0);
}
uint64_t jumblr_getcoinaddr(char *coinaddr,struct destbuf *scriptPubKey,struct coin777 *coin,char *txid,int32_t vout)
{
char *rawtransaction,*txidstr,*asmstr; uint64_t value = 0; int32_t n,m,len,reqSigs; cJSON *json,*scriptobj,*array,*item,*hexobj;
scriptPubKey->buf[0] = 0;
if ( (rawtransaction= _get_transaction(coin->name,coin->serverport,coin->userpass,txid)) == 0 )
{
printf("jumblr_getprivkey: error getting (%s)\n",txid);
return(0);
}
if ( (json= cJSON_Parse(rawtransaction)) != 0 )
{
if ( (txidstr= jstr(json,"txid")) == 0 || strcmp(txidstr,txid) != 0 )
{
printf("jumblr_getcoinaddr no txid or mismatch\n");
free_json(json);
free(rawtransaction);
return(0);
}
if ( (array= jarray(&n,json,"vout")) != 0 && vout < n && (item= jitem(array,vout)) != 0 )
{
reqSigs = (int32_t)get_cJSON_int(item,"reqSigs");
value = conv_cJSON_float(item,"value");
scriptobj = cJSON_GetObjectItem(item,"scriptPubKey");
printf("ITEM.(%s)\n",jprint(item,0));
if ( scriptobj != 0 )
{
printf("script.(%s)\n",jprint(scriptobj,0));
script_coinaddr(coinaddr,scriptobj);
hexobj = cJSON_GetObjectItem(scriptobj,"hex");
if ( scriptPubKey != 0 && hexobj != 0 )
copy_cJSON(scriptPubKey,hexobj);
else
{
// OP_DUP OP_HASH160 f563e867027dedd109c9bb5f3354c3cc41dc7c7f OP_EQUALVERIFY OP_CHECKSIG
// 0318d4f6cdcbe6c822b979fc318dbe4ad58287223c8fb57b7bec0c88cd58a4b16a OP_CHECKSIG
if ( (asmstr= jstr(scriptobj,"asm")) != 0 )
{
len = (int32_t)strlen(asmstr);
m = (int32_t)strlen(" OP_EQUALVERIFY OP_CHECKSIG");
if ( strncmp(asmstr,"OP_DUP OP_HASH160 ",strlen("OP_DUP OP_HASH160 ")) == 0 && strcmp(&asmstr[len - m]," OP_EQUALVERIFY OP_CHECKSIG") == 0 )
set_spendscript(scriptPubKey->buf,coinaddr);
else
{
printf("nonstandard.(%s)\n",&asmstr[len - m]);
m = (int32_t)strlen(" OP_CHECKSIG");
if ( strcmp(&asmstr[len - m]," OP_CHECKSIG") == 0 )
{
printf("key sig (%s)\n",asmstr);
sprintf(scriptPubKey->buf,"%02x",(len-m)/2);
memcpy(&scriptPubKey->buf[2],asmstr,(len - m));
scriptPubKey->buf[2 + (len - m)] = 0;
strcat(scriptPubKey->buf,"ac");
}
}
}
}
} else printf("null scriptobj.%p (%s)\n",scriptobj,coinaddr);
}
free_json(json);
}
free(rawtransaction);
return(value);
}
char *jumblr_getprivkey(uint64_t *valuep,struct destbuf *scriptPubKey,uint32_t *locktimep,struct coin777 *coin,char *txid,int32_t vout)
{
char *rawtransaction,*txidstr,*privkey=0,coinaddr[64]; uint64_t value = 0; int32_t n,reqSigs; cJSON *json,*scriptobj,*array,*item,*hexobj;
*locktimep = -1;
scriptPubKey->buf[0] = 0;
if ( (rawtransaction= _get_transaction(coin->name,coin->serverport,coin->userpass,txid)) == 0 )
{
printf("jumblr_getprivkey: error getting (%s)\n",txid);
return(0);
}
if ( (json= cJSON_Parse(rawtransaction)) != 0 )//get_decoderaw_json(coin,rawtransaction)) != 0 )
{
*locktimep = (int32_t)get_cJSON_int(json,"locktime");
if ( (txidstr= jstr(json,"txid")) == 0 || strcmp(txidstr,txid) != 0 )
{
printf("jumblr_getprivkey no txid or mismatch\n");
free_json(json);
free(rawtransaction);
return(0);
}
//printf("txidstr.(%s) vout.%d\n",txidstr,vout);
if ( (array= jarray(&n,json,"vout")) != 0 && (item= jitem(array,vout)) != 0 )
{
scriptobj = cJSON_GetObjectItem(item,"scriptPubKey");
if ( scriptobj != 0 && script_coinaddr(coinaddr,scriptobj) == 0 )
{
reqSigs = (int32_t)get_cJSON_int(item,"reqSigs");
value = conv_cJSON_float(item,"value");
hexobj = cJSON_GetObjectItem(scriptobj,"hex");
if ( scriptPubKey != 0 && hexobj != 0 )
copy_cJSON(scriptPubKey,hexobj);
privkey = dumpprivkey(coin->name,coin->serverport,coin->userpass,coinaddr);
} else printf("null scriptobj.%p (%s)\n",scriptobj,coinaddr);
}
free_json(json);
}
free(rawtransaction);
if ( valuep != 0 )
*valuep = value;
return(privkey);
}
cJSON *cointx_vins_json_params(struct coin777 *coin,char *rawbytes)
{
int32_t i; cJSON *json,*array; char coinaddr[128]; struct destbuf scriptPubKey; struct cointx_info *cointx;
array = cJSON_CreateArray();
printf("convert.(%s)\n",rawbytes);
if ( (cointx= _decode_rawtransaction(rawbytes,coin->mgw.oldtx_format)) != 0 )
{
disp_cointx(cointx);
for (i=0; i<cointx->numinputs; i++)
{
json = cJSON_CreateObject();
jaddstr(json,"txid",cointx->inputs[i].tx.txidstr);
jaddnum(json,"vout",cointx->inputs[i].tx.vout);
if ( cointx->inputs[i].sigs[0] != 0 )
jaddstr(json,"scriptPubKey",cointx->inputs[i].sigs);
else
{
jumblr_getcoinaddr(coinaddr,&scriptPubKey,coin,cointx->inputs[i].tx.txidstr,cointx->inputs[i].tx.vout);
jaddstr(json,"scriptPubKey",scriptPubKey.buf);
}
cJSON_AddItemToArray(array,json);
}
free(cointx);
}
return(array);
}
char *jumblr_signraw_json_params(struct coin777 *coin,char *rawbytes)
{
char *paramstr = 0; cJSON *array,*rawobj,*vinsobj;//,*keysobj;char *coinaddrs[MAX_SUBATOMIC_INPUTS+1],
if ( (rawobj= cJSON_CreateString(rawbytes)) != 0 )
{
if ( (vinsobj= cointx_vins_json_params(coin,rawbytes)) != 0 )
{
array = cJSON_CreateArray();
jaddi(array,rawobj);
jaddi(array,vinsobj);
//cJSON_AddItemToArray(array,keysobj);
paramstr = jprint(array,1);
}
else free_json(rawobj);
}
return(paramstr);
}
int32_t jumblr_signtx(char *signedtx,unsigned long destsize,struct coin777 *coin,char *signparams)
{
cJSON *json,*compobj; char *retstr,*deststr; uint32_t completed = 0;
signedtx[0] = 0;
//printf("cp.%d vs %d: subatomic_signtx rawbytes.(%s)\n",cp->coinid,coinid,rawbytes);
if ( coin != 0 && signparams != 0 )
{
_stripwhite(signparams,' ');
printf("got signparams.(%s)\n",signparams);
if ( (retstr= bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"signrawtransaction",signparams)) != 0 )
{
//printf("got retstr.(%s)\n",retstr);
if ( (json= cJSON_Parse(retstr)) != 0 )
{
if ( (deststr= jstr(json,"hex")) != 0 )
{
compobj = cJSON_GetObjectItem(json,"complete");
if ( compobj != 0 )
completed = ((compobj->type&0xff) == cJSON_True);
if ( strlen(deststr) > destsize )
printf("sign_rawtransaction: strlen(deststr) %ld > %ld destize\n",(long)strlen(deststr),destsize);
else strcpy(signedtx,deststr);
} else printf("cant get hex from.(%s)\n",retstr);
free_json(json);
} else printf("json parse error.(%s)\n",retstr);
free(retstr);
} else printf("error signing rawtx\n");
} else printf("error generating signparams\n");
return(completed);
}
char *jumblr_signvin(char *sigstr,struct coin777 *coin,char *signedtx,int32_t bufsize,void *bpkey,char *pubP,struct cointx_info *refT,int32_t redeemi,char *rawtx)
{
// signrawtransaction <hex string> [{"txid":txid,"vout":n,"scriptPubKey":hex},...] [<privatekey1>,...]
char hexstr[4096],redeem[2048]; bits256 hash2; uint8_t *data,sigbuf[1024];
struct cointx_info *T; int32_t i; void *sig = NULL; size_t siglen = 0; struct cointx_input *vin;
sigstr[0] = 0;
if ( 1 )
{
char *paramstr; cJSON *vinarray,*item,*array = cJSON_CreateArray();
vinarray = cJSON_CreateArray();
jaddistr(array,rawtx);
for (i=0; i<refT->numinputs; i++)
{
vin = &refT->inputs[i];
item = cJSON_CreateObject();
jaddstr(item,"txid",vin->tx.txidstr);
jaddnum(item,"vout",vin->tx.vout);
jaddstr(item,"scriptPubKey",vin->sigs);
jaddi(vinarray,item);
}
jaddi(array,vinarray);
paramstr = jprint(array,1);
if ( jumblr_signtx(signedtx,bufsize,coin,paramstr) > 0 )
printf("SIGS completed\n");
if ( signedtx[0] != 0 )
{
if ( (T= _decode_rawtransaction(signedtx,coin->mgw.oldtx_format)) != 0 )
{
strcpy(sigstr,T->inputs[redeemi].sigs);
free(T);
return(sigstr);
}
}
return(0);
}
if ( (T = calloc(1,sizeof(*T))) == 0 )
{
printf("unexpected out of mem in jumblr_signvin\n");
return(0);
}
*T = *refT;
vin = &T->inputs[redeemi];
safecopy(redeem,vin->sigs,sizeof(redeem));
fprintf(stderr,"redeemi.%d numinputs.%d\n",redeemi,T->numinputs);
for (i=0; i<T->numinputs; i++)
if ( i != redeemi )
strcpy(T->inputs[i].sigs,"00");
vin->sequence = (uint32_t)-1;
T->nlocktime = 0;
data = malloc(65536);
disp_cointx(T);
emit_cointx(&hash2,data,sizeof(data),T,coin->mgw.oldtx_format,SIGHASH_ALL);
free(data);
if ( bp_sign(bpkey,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 && sig != 0 )
{
memcpy(sigbuf,sig,siglen);
free(sig);
sigbuf[siglen++] = SIGHASH_ALL;
init_hexbytes_noT(hexstr,sigbuf,(int32_t)siglen);
sprintf(vin->sigs,"%02x%s%02x%s",(uint32_t)siglen,hexstr,(uint32_t)strlen(pubP)/2,pubP);
strcpy(sigstr,vin->sigs);
printf("after P.(%s) siglen.%02x -> %s pubP.(%s)\n",sigstr,(uint32_t)siglen,vin->sigs,pubP);
}
free(T);
if ( sigstr[0] != 0 )
return(sigstr);
else return(0);
}
int32_t script_has_coinaddr(cJSON *scriptobj,char *coinaddr)
{
int32_t i,n; struct destbuf buf; cJSON *addresses,*addrobj;
if ( scriptobj == 0 )
return(0);
addresses = cJSON_GetObjectItem(scriptobj,"addresses");
if ( addresses != 0 )
{
n = cJSON_GetArraySize(addresses);
for (i=0; i<n; i++)
{
addrobj = cJSON_GetArrayItem(addresses,i);
copy_cJSON(&buf,addrobj);
if ( strcmp(buf.buf,coinaddr) == 0 )
return(1);
}
}
return(0);
}
cJSON *get_decoderaw_json(struct coin777 *coin,char *rawtransaction)
{
char *str,*retstr; cJSON *json = 0;
str = malloc(strlen(rawtransaction)+4);
//printf("got rawtransaction.(%s)\n",rawtransaction);
sprintf(str,"\"%s\"",rawtransaction);
if ( (retstr= bitcoind_passthru(coin->name,coin->serverport,coin->userpass,"decoderawtransaction",str)) != 0 && retstr[0] != 0 )
{
//printf("got decodetransaction.(%s)\n",retstr);
json = cJSON_Parse(retstr);
} else printf("error decoding.(%s)\n",str);
if ( retstr != 0 )
free(retstr);
free(str);
return(json);
}
char *subatomic_decodetxid(int64_t *valuep,struct destbuf *scriptPubKey,uint32_t *locktimep,struct coin777 *coin,char *rawtransaction,char *mycoinaddr)
{
char *txidstr,checkasmstr[1024],*asmstr,*txid = 0; uint64_t value = 0; int32_t i,n,nval,reqSigs; cJSON *json,*scriptobj,*array,*item,*hexobj;
*locktimep = -1;
if ( (json= get_decoderaw_json(coin,rawtransaction)) != 0 )
{
*locktimep = (int32_t)get_cJSON_int(json,"locktime");
if ( (txidstr= jstr(json,"txid")) == 0 )
{
printf("subatomic_decodetxid no txid\n");
return(0);
}
txid = clonestr(txidstr);
array = cJSON_GetObjectItem(json,"vout");
if ( mycoinaddr != 0 && is_cJSON_Array(array) != 0 )
{
n = cJSON_GetArraySize(array);
for (i=0; i<n; i++)
{
item = cJSON_GetArrayItem(array,i);
hexobj = 0;
scriptobj = cJSON_GetObjectItem(item,"scriptPubKey");
if ( mycoinaddr != 0 && scriptobj != 0 && script_has_coinaddr(scriptobj,mycoinaddr) != 0 )
{
nval = (int32_t)get_cJSON_int(item,"n");
if ( nval == i )
{
reqSigs = (int32_t)get_cJSON_int(item,"reqSigs");
value = conv_cJSON_float(item,"value");
hexobj = cJSON_GetObjectItem(scriptobj,"hex");
if ( scriptPubKey != 0 && hexobj != 0 )
copy_cJSON(scriptPubKey,hexobj);
if ( reqSigs == 1 && hexobj != 0 )
{
sprintf(checkasmstr,"OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG","need to figure out how ot gen magic number");
if ( (asmstr= jstr(scriptobj,"asm")) != 0 && strcmp(asmstr,checkasmstr) != 0 )
printf("warning: (%s) != check.(%s)\n",asmstr,checkasmstr);
}
}
}
}
}
}
if ( valuep != 0 )
*valuep = value;
return(txid);
}
cJSON *subatomic_vins_json_params(struct coin777 *coin,struct subatomic_rawtransaction *rp)
{
int32_t i; cJSON *json,*array; struct subatomic_unspent_tx *up;
array = cJSON_CreateArray();
for (i=0; i<rp->numinputs; i++)
{
up = &rp->inputs[i];
json = cJSON_CreateObject();
jaddstr(json,"txid",up->txid.buf);
jaddnum(json,"vout",up->vout);
if ( up->scriptPubKey.buf[0] != 0 )
jaddstr(json,"scriptPubKey",up->scriptPubKey.buf);
if ( up->redeemScript.buf[0] != 0 )
jaddstr(json,"redeemScript",up->redeemScript.buf);
cJSON_AddItemToArray(array,json);
}
return(array);
}
cJSON *subatomic_privkeys_json_params(struct coin777 *coin,char **coinaddrs,int32_t n)
{
int32_t i; char *privkey; cJSON *array = cJSON_CreateArray();
//sprintf(walletkey,"[\"%s\",%d]",Global_subatomic->NXTADDR,BITCOIN_WALLET_UNLOCKSECONDS);
// locking first avoids error, hacky but no time for wallet fiddling now
//bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"walletlock",0);
//bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"walletpassphrase",walletkey);
for (i=0; i<n; i++)
{
if ( coinaddrs[i][0] != 0 )
{
printf("privkeys.(%s)\n",coinaddrs[i]);
if ( (privkey= dumpprivkey(coin->name,coin->serverport,coin->userpass,coinaddrs[i])) != 0 )
{
jaddistr(array,privkey);
free(privkey);
}
}
}
return(array);
}
char *subatomic_signraw_json_params(char *skipaddr,char *coinaddr,struct coin777 *coin,struct subatomic_rawtransaction *rp,char *rawbytes)
{
int32_t i,j,flag; char *coinaddrs[MAX_SUBATOMIC_INPUTS+1],*paramstr = 0; cJSON *array,*rawobj,*vinsobj,*keysobj;
if ( (rawobj= cJSON_CreateString(rawbytes)) != 0 )
{
if ( (vinsobj= subatomic_vins_json_params(coin,rp)) != 0 )
{
// printf("add %d inputs skipaddr.%s coinaddr.%s\n",rp->numinputs,skipaddr,coinaddr);
for (i=flag=j=0; i<rp->numinputs; i++)
{
if ( skipaddr == 0 || strcmp(rp->inputs[i].address.buf,skipaddr) != 0 )
{
printf("i.%d j.%d flag.%d %s\n",i,j,flag,rp->inputs[i].address.buf);
coinaddrs[j] = rp->inputs[i].address.buf;
if ( coinaddr != 0 && strcmp(coinaddrs[j],coinaddr) == 0 )
flag++;
j++;
}
}
//printf("i.%d j.%d flag.%d\n",i,j,flag);
//if ( coinaddr != 0 && flag == 0 )
//coinaddrs[j++] = coinaddr;
coinaddrs[j] = 0;
keysobj = subatomic_privkeys_json_params(coin,coinaddrs,j);
if ( keysobj != 0 )
{
array = cJSON_CreateArray();
cJSON_AddItemToArray(array,rawobj);
cJSON_AddItemToArray(array,vinsobj);
cJSON_AddItemToArray(array,keysobj);
paramstr = cJSON_Print(array);
free_json(array);
}
else free_json(vinsobj);
}
else free_json(rawobj);
}
return(paramstr);
}
char *subatomic_signtx(char *skipaddr,uint32_t *lockedblockp,int64_t *valuep,char *coinaddr,char *signedtx,unsigned long destsize,struct coin777 *coin,struct subatomic_rawtransaction *rp,char *rawbytes)
{
cJSON *json,*compobj; char *retstr,*deststr,*signparams,*txid = 0; uint32_t locktime = 0;
rp->txid[0] = signedtx[0] = 0;
rp->completed = -1;
//printf("cp.%d vs %d: subatomic_signtx rawbytes.(%s)\n",cp->coinid,coinid,rawbytes);
if ( coin != 0 && (signparams= subatomic_signraw_json_params(skipaddr,coinaddr,coin,rp,rawbytes)) != 0 )
{
_stripwhite(signparams,' ');
//printf("got signparams.(%s)\n",signparams);
if ( (retstr= bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"signrawtransaction",signparams)) != 0 )
{
//printf("got retstr.(%s)\n",retstr);
if ( (json= cJSON_Parse(retstr)) != 0 )
{
if ( (deststr= jstr(json,"hex")) != 0 )
{
compobj = cJSON_GetObjectItem(json,"complete");
if ( compobj != 0 )
rp->completed = ((compobj->type&0xff) == cJSON_True);
if ( strlen(deststr) > destsize )
printf("sign_rawtransaction: strlen(deststr) %ld > %ld destize\n",(long)strlen(deststr),destsize);
else
{
strcpy(signedtx,deststr);
txid = subatomic_decodetxid(valuep,0,&locktime,coin,deststr,coinaddr);
if ( txid != 0 )
{
safecopy(rp->txid,txid,sizeof(rp->txid));
free(txid);
txid = rp->txid;
}
// printf("got signedtransaction -> txid.(%s) %.8f\n",rp->txid,dstr(valuep!=0?*valuep:0));
}
} else printf("cant get hex from.(%s)\n",retstr);
free_json(json);
} else printf("json parse error.(%s)\n",retstr);
free(retstr);
} else printf("error signing rawtx\n");
free(signparams);
} else printf("error generating signparams\n");
if ( lockedblockp != 0 )
*lockedblockp = locktime;
return(txid);
}
cJSON *subatomic_vouts_json_params(struct subatomic_rawtransaction *rp)
{
int32_t i; cJSON *json,*obj;
json = cJSON_CreateObject();
for (i=0; i<rp->numoutputs; i++)
{
obj = cJSON_CreateNumber((double)rp->destamounts[i]/SATOSHIDEN);
cJSON_AddItemToObject(json,rp->destaddrs[i],obj);
}
// printf("numdests.%d (%s)\n",rp->numoutputs,cJSON_Print(json));
return(json);
}
char *subatomic_rawtxid_json(struct coin777 *coin,struct subatomic_rawtransaction *rp)
{
char *paramstr = 0; cJSON *array,*vinsobj,*voutsobj;
if ( (vinsobj= subatomic_vins_json_params(coin,rp)) != 0 )
{
if ( (voutsobj= subatomic_vouts_json_params(rp)) != 0 )
{
array = cJSON_CreateArray();
cJSON_AddItemToArray(array,vinsobj);
cJSON_AddItemToArray(array,voutsobj);
paramstr = cJSON_Print(array);
free_json(array); // this frees both vinsobj and voutsobj
}
else free_json(vinsobj);
}
// printf("subatomic_rawtxid_json.%s\n",paramstr);
return(paramstr);
}
uint64_t subatomic_donation(struct coin777 *coin,uint64_t amount)
{
uint64_t donation = 0;
if ( coin->donationaddress[0] != 0 )
{
donation = amount >> 11;
if ( donation < coin->mgw.txfee )
donation = coin->mgw.txfee;
}
return(donation);
}
char *gather_account_addresses(struct coin777 *coin,char *account)
{
cJSON *array,*retarray,*subarray,*item; int32_t i,j,m,n; char *acct;
//printf("call listaddressgroupings\n");
if ( (array= _get_localaddresses(coin->name,coin->serverport,coin->userpass)) != 0 )
{
retarray = cJSON_CreateArray();
n = cJSON_GetArraySize(array);
for (i=0; i<n; i++)
{
if ( (subarray= jitem(array,i)) != 0 )
{
//printf("%d of %d: %s\n",i,n,jprint(subarray,0));
if ( is_cJSON_Array(subarray) != 0 && (m= cJSON_GetArraySize(subarray)) > 0 )
{
for (j=0; j<m; j++)
{
if ( (item= jitem(subarray,j)) != 0 && is_cJSON_Array(item) != 0 && cJSON_GetArraySize(item) > 2 )
{
if ( (acct= jstr(jitem(item,2),0)) != 0 && strcmp(acct,account) == 0 )
{
//printf("gather.(%s) %s\n",jstr(jitem(item,0),0),account);
jaddistr(retarray,jstr(jitem(item,0),0));
}
} //else printf("skip item.%p, %d %d\n",item,is_cJSON_Array(item),cJSON_GetArraySize(item));
}
}
}
}
free_json(array);
if ( cJSON_GetArraySize(retarray) == 0 )
{
free_json(retarray);
return(0);
}
else return(jprint(retarray,1));
}
else return(0);
}
struct subatomic_unspent_tx *gather_unspents(uint64_t *totalp,int32_t *nump,struct coin777 *coin,char *account)
{
int32_t i,j,num; struct subatomic_unspent_tx *ups = 0; char *params,*addrs,*retstr; cJSON *json,*item;
/*{
"txid" : "1ccd2a9d0f8d690ed13b6768fc6c041972362f5531922b6b152ed2c98d3fe113",
"vout" : 1,
"address" : "DK3nxu6GshBcQNDMqc66ARcwqDZ1B5TJe5",
"scriptPubKey" : "76a9149891029995222077889b36c77e2b85690878df9088ac",
"amount" : 2.00000000,
"confirmations" : 72505
},*/
*totalp = *nump = 0;
if ( account != 0 && account[0] != 0 )
{
if ( (addrs= gather_account_addresses(coin,account)) != 0 )
{
if ( (params = calloc(1,strlen(addrs) + 128)) == 0 )
{
free(addrs);
return(0);
}
addrs[strlen(addrs)-1] = 0;
sprintf(params,"[%d, 99999999, [%s]]",coin->minconfirms,addrs+1);
free(addrs);
} else return(0);
}
else
{
if ( (params = calloc(1,128)) == 0 )
return(0);
sprintf(params,"%d, 99999999",coin->minconfirms);
}
//printf("issue listunspent.(%s)\n",params);
if ( (retstr= bitcoind_passthru(coin->name,coin->serverport,coin->userpass,"listunspent",params)) != 0 )
{
//printf("unspents (%s)\n",retstr);
if ( (json= cJSON_Parse(retstr)) != 0 )
{
if ( is_cJSON_Array(json) != 0 && (num= cJSON_GetArraySize(json)) > 0 )
{
ups = calloc(num,sizeof(struct subatomic_unspent_tx));
for (i=j=0; i<num; i++)
{
item = cJSON_GetArrayItem(json,i);
copy_cJSON(&ups[j].address,cJSON_GetObjectItem(item,"address"));
//if ( skipcoinaddr == 0 || strcmp(skipcoinaddr,ups[j].address.buf) != 0 )
{
copy_cJSON(&ups[j].txid,cJSON_GetObjectItem(item,"txid"));
copy_cJSON(&ups[j].scriptPubKey,cJSON_GetObjectItem(item,"scriptPubKey"));
ups[j].vout = (int32_t)get_cJSON_int(item,"vout");
ups[j].amount = conv_cJSON_float(item,"amount");
ups[j].confirmations = (int32_t)get_cJSON_int(item,"confirmations");
*totalp += ups[j].amount;
j++;
}
}
*nump = j;
if ( j > 0 )
{
int _decreasing_signedint64(const void *a,const void *b);
if ( j > 1 )
qsort(ups,j,sizeof(*ups),_decreasing_signedint64);
if ( coin->changeaddr[0] == 0 )
strcpy(coin->changeaddr,ups[0].address.buf);
//for (i=0; i<j; i++)
//printf("%s/v%-3d %13.6f %s confs.%-6d | total %.6f\n",ups[i].txid.buf,ups[i].vout,dstr(ups[i].amount),ups[i].address.buf,ups[i].confirmations,dstr(*totalp));
}
}
free_json(json);
}
free(retstr);
}
free(params);
if ( *nump == 0 )
printf("no (%s) unspents for (%s)\n",coin->name,account != 0 ? account : "");
return(ups);
}
struct subatomic_unspent_tx *subatomic_bestfit(struct coin777 *coin,struct subatomic_unspent_tx *unspents,int32_t numunspents,uint64_t value,int32_t mode)
{
int32_t i; uint64_t above,below,gap,atx_value; struct subatomic_unspent_tx *vin,*abovevin,*belowvin;
abovevin = belowvin = 0;
for (above=below=i=0; i<numunspents; i++)
{
vin = &unspents[i];
atx_value = vin->amount;
//printf("(%.8f vs %.8f)\n",dstr(atx_value),dstr(value));
if ( atx_value == value )
return(vin);
else if ( atx_value > value )
{
gap = (atx_value - value);
if ( above == 0 || gap < above )
{
above = gap;
abovevin = vin;
}
}
else if ( mode == 0 )
{
gap = (value - atx_value);
if ( below == 0 || gap < below )
{
below = gap;
belowvin = vin;
}
}
}
if ( (vin= (abovevin != 0) ? abovevin : belowvin) == 0 && mode == 1 )
vin = unspents;
return(vin);
}
int64_t subatomic_calc_rawinputs(struct coin777 *coin,struct subatomic_rawtransaction *rp,uint64_t amount,struct subatomic_unspent_tx *ups,int32_t num,uint64_t donation)
{
uint64_t sum = 0; struct subatomic_unspent_tx *up; int32_t i;
rp->inputsum = rp->numinputs = 0;
printf("unspent num %d, amount %.8f vs donation %.8f txfee %.8f\n",num,dstr(amount),dstr(donation),dstr(coin->mgw.txfee));
if ( coin == 0 || num == 0 ) // (donation + coin->mgw.txfee) > amount ||
return(0);
amount += coin->mgw.txfee + donation;
for (i=0; i<num&&i<((int32_t)(sizeof(rp->inputs)/sizeof(*rp->inputs))); i++)
{
if ( (up= subatomic_bestfit(coin,ups,num,amount,0)) != 0 )
{
sum += up->amount;
rp->inputs[rp->numinputs++] = *up;
if ( sum >= amount )
{
rp->amount = (amount - coin->mgw.txfee - donation);
rp->change = (sum - amount);
rp->inputsum = sum;
printf("numinputs %d sum %.8f vs amount %.8f change %.8f -> txfee %.8f\n",rp->numinputs,dstr(rp->inputsum),dstr(amount),dstr(rp->change),dstr(sum - rp->change - rp->amount));
return(rp->inputsum);
}
}
printf("error getting bestfit unspent\n");
break;
}
printf("i.%d error numinputs %d sum %.8f\n",i,rp->numinputs,dstr(rp->inputsum));
return(0);
}
char *subatomic_gen_rawtransaction(char *skipaddr,struct coin777 *coin,struct subatomic_rawtransaction *rp,char *signcoinaddr,uint32_t locktime,uint32_t vin0sequenceid,char *redeem0script)
{
char *rawparams,*retstr,*txid=0; int64_t value; long len; struct cointx_info *cointx;
if ( (rawparams= subatomic_rawtxid_json(coin,rp)) != 0 )
{
_stripwhite(rawparams,' ');
//printf("create.(%s)\n",rawparams);
if ( (retstr= bitcoind_RPC(0,coin->name,coin->serverport,coin->userpass,"createrawtransaction",rawparams)) != 0 )
{
if ( retstr[0] != 0 )
{
// printf("calc_rawtransaction retstr.(%s)\n",retstr);
safecopy(rp->rawtransaction,retstr,sizeof(rp->rawtransaction));
len = strlen(rp->rawtransaction);
if ( len < 8 )
{
printf("funny rawtransactionlen %ld??\n",len);
free(rawparams);
return(0);
}
if ( locktime != 0 || redeem0script != 0 )
{
if ( (cointx= _decode_rawtransaction(rp->rawtransaction,coin->mgw.oldtx_format)) != 0 )
{
//printf("%s\n->\n",rp->rawtransaction);
cointx->nlocktime = locktime;
cointx->inputs[0].sequence = vin0sequenceid;
if ( redeem0script != 0 )
safecopy(cointx->outputs[0].script,redeem0script,sizeof(cointx->outputs[0].script));
_emit_cointx(rp->rawtransaction,sizeof(rp->rawtransaction),cointx,coin->mgw.oldtx_format);
_validate_decoderawtransaction(rp->rawtransaction,cointx,coin->mgw.oldtx_format);
//printf("spliced tx.(%s)\n",rp->rawtransaction);
free(cointx);
}
printf("locktime.%d sequenceid.%d signcoinaddr.(%s)\n",locktime,vin0sequenceid,signcoinaddr!=0?signcoinaddr:"");
}
if ( signcoinaddr != 0 )
{
txid = subatomic_signtx(skipaddr,0,&value,signcoinaddr,rp->signedtransaction,sizeof(rp->signedtransaction),coin,rp,rp->rawtransaction);
printf("signedtxid.%s\n",txid);
}
}
free(retstr);
} else printf("error creating rawtransaction from.(%s)\n",rawparams);
free(rawparams);
} else printf("error creating rawparams\n");
return(txid);
}
char *subatomic_signp2sh(char *sigstr,struct coin777 *coin,struct cointx_info *refT,int32_t msigflag,int32_t lockblocks,int32_t redeemi,char *redeemscript,int32_t p2shflag,char *privkeystr,int32_t privkeyind,char *othersig,char *otherpubkey,char *checkprivkey)
{
char hexstr[1024],pubP[128],*sig0,*sig1; bits256 hash2; uint8_t data[4096],sigbuf[512]; struct bp_key key,keyV;
struct cointx_info *T; int32_t i,n; void *sig = NULL; size_t siglen = 0; struct cointx_input *vin;
if ( (T= calloc(1,sizeof(*T))) == 0 )
return(0);
if ( privkeystr != 0 )
btc_setprivkey(&key,privkeystr);
*T = *refT; vin = &T->inputs[redeemi];
for (i=0; i<T->numinputs; i++)
strcpy(T->inputs[i].sigs,"00");
strcpy(vin->sigs,redeemscript);
if ( msigflag == 0 )
{
vin->sequence = (uint32_t)-1;
T->nlocktime = 0;
}
else
{
if ( vin->sequence == 0 )
vin->sequence = (uint32_t)time(NULL);
if ( T->nlocktime == 0 && lockblocks != 0 )
{
if ( lockblocks != 0 )
{
coin->ramchain.RTblocknum = _get_RTheight(&coin->ramchain.lastgetinfo,coin->name,coin->serverport,coin->userpass,coin->ramchain.RTblocknum);
if ( coin->ramchain.RTblocknum == 0 )
{
printf("cant get RTblocknum for %s\n",coin->name);
free(T);
return(0);
}
lockblocks += coin->ramchain.RTblocknum;
}
T->nlocktime = lockblocks;
}
}
//disp_cointx(&T);
emit_cointx(&hash2,data,sizeof(data),T,coin->mgw.oldtx_format,SIGHASH_ALL);
//printf("HASH2.(%llx)\n",(long long)hash2.txid);
if ( msigflag != 0 )
{
if ( othersig != 0 )
{
n = (int32_t)strlen(otherpubkey) >> 1;
decode_hex(data,n,otherpubkey);
if ( bp_key_init(&keyV) == 0 || bp_pubkey_set(&keyV,data,n) == 0 )
{
printf("cant set pubkey\n");
free(T);
return(0);
}
n = (int32_t)strlen(othersig) >> 1;
decode_hex(data,n,othersig);
if ( data[n-1] != SIGHASH_ALL )
{
printf("othersig.(%s) hash type mismatch %d != %d\n",othersig,data[n-1],SIGHASH_ALL);
free(T);
return(0);
}
if ( bp_verify(&keyV,hash2.bytes,sizeof(hash2),data,n-1) == 0 )
{
hexstr[0] = 0;
if ( checkprivkey != 0 )
{
//printf("checkprivkey.(%s)\n",checkprivkey);
btc_setprivkey(&keyV,checkprivkey);
void *dispkey; size_t slen;
bp_privkey_get(&keyV,&dispkey,&slen);
//for (i=0; i<slen; i++)
// printf("%02x",((uint8_t *)dispkey)[i]);
//printf(" checkkey\n");
if ( bp_sign(&keyV,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 )
init_hexbytes_noT(hexstr,sigbuf,(int32_t)siglen);
}
printf("othersig.(%s) doesnt verify vs (%s)\n",othersig,hexstr);
//return(0);
} else printf("SIG.%d VERIFIED\n",privkeyind ^ 1);
}
if ( privkeystr != 0 )
{
void *dispkey; size_t slen;
bp_privkey_get(&key,&dispkey,&slen);
//for (i=0; i<slen; i++)
// printf("%02x",((uint8_t *)dispkey)[i]);
//printf(" dispkey.(%s)\n",privkeystr);
if ( bp_sign(&key,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 )
{
memcpy(sigbuf,sig,siglen);
sigbuf[siglen++] = SIGHASH_ALL;
init_hexbytes_noT(hexstr,sigbuf,(int32_t)siglen);
if ( sigstr != 0 )
strcpy(sigstr,hexstr);
if ( privkeyind == 0 )
sig0 = hexstr, sig1 = othersig != 0 ? othersig : "";
else sig1 = hexstr, sig0 = othersig != 0 ? othersig : "";
sprintf(vin->sigs,"00%02x%s%02x%s51",(int32_t)strlen(sig0)>>1,sig0,(int32_t)strlen(sig1)>>1,sig1);
//printf("after A.(%s) othersig.(%s) siglen.%02lx -> (%s)\n",hexstr,othersig != 0 ? othersig : "",siglen,vin->sigs);
}
else
{
printf("error signing\n");
free(T);
return(0);
}
}
else vin->sigs[0] = 0;
}
else
{
if ( bp_sign(&key,hash2.bytes,sizeof(hash2),&sig,&siglen) != 0 && btc_getpubkey(pubP,data,&key) > 0 )
{
memcpy(sigbuf,sig,siglen);
sigbuf[siglen++] = SIGHASH_ALL;
init_hexbytes_noT(hexstr,sigbuf,(int32_t)siglen);
sprintf(vin->sigs,"%02x%s%02x%s00",(int32_t)siglen,hexstr,(int32_t)strlen(pubP)/2,pubP);
//printf("after P.(%s) siglen.%02lx\n",vin->sigs,siglen);
}
}
if ( vin->sigs[0] != 0 )
{
if ( p2shflag != 0 )
sprintf(&vin->sigs[strlen(vin->sigs)],"4c%02x",(int32_t)strlen(redeemscript)/2);
sprintf(&vin->sigs[strlen(vin->sigs)],"%s",redeemscript);
}
//printf("scriptSig.(%s)\n",vin->sigs);
_emit_cointx(hexstr,sizeof(hexstr),T,coin->mgw.oldtx_format);
//disp_cointx(&T);
free(T);
return(clonestr(hexstr));
//printf("T.msigredeem %d -> (%s)\n",msigflag,hexstr);
}
char *subatomic_fundingtx(char *refredeemscript,struct subatomic_rawtransaction *funding,struct coin777 *coin,char *mypubkey,char *otherpubkey,char *pkhash,uint64_t amount,int32_t lockblocks)
{
char scriptPubKey[128],mycoinaddr[64],p2shaddr[64],sigstr[512],*refundtx=0,*redeemscript,*txid=0; struct subatomic_unspent_tx *utx;
uint64_t total,donation; int32_t num,n=0,lockblock = 0; struct cointx_info *refT; uint8_t rmd160[20];
memset(funding,0,sizeof(*funding));
refredeemscript[0] = 0;
if ( (redeemscript= create_atomictx_scripts(coin->p2shtype,scriptPubKey,p2shaddr,mypubkey,otherpubkey,pkhash)) != 0 )
{
strcpy(refredeemscript,redeemscript);
if ( btc_coinaddr(mycoinaddr,coin->addrtype,mypubkey) != 0 && (utx= gather_unspents(&total,&num,coin,0)) != 0 )
{
donation = subatomic_donation(coin,amount);
//printf("CREATE FUNDING TX.(%s) [%s %s %s] for %.8f -> %s locktime.%u donation %.8f\n",coin->name,mypubkey,otherpubkey,pkhash,dstr(amount),p2shaddr,lockblock,dstr(donation));
if ( subatomic_calc_rawinputs(coin,funding,amount,utx,num,donation) >= amount )
{
if ( funding->amount == amount && funding->change == (funding->inputsum - amount - coin->mgw.txfee - donation) )
{
safecopy(funding->destaddrs[n],p2shaddr,sizeof(funding->destaddrs[n]));
funding->destamounts[n] = amount;
n++;
}
if ( donation != 0 )
{
if ( coin->donationaddress[0] != 0 )
{
safecopy(funding->destaddrs[n],coin->donationaddress,sizeof(funding->destaddrs[n]));
funding->destamounts[n] = donation;
n++;
} else funding->change += donation;
}
if ( funding->change != 0 )
{
if ( coin->changeaddr[0] == 0 )
{
printf("no changeaddress for (%s)\n",coin->name);
return(0);
}
safecopy(funding->destaddrs[n],coin->changeaddr,sizeof(funding->destaddrs[n]));
funding->destamounts[n] = funding->change;
n++;
}
funding->numoutputs = n;
if ( (txid= subatomic_gen_rawtransaction(0,coin,funding,p2shaddr,lockblock,lockblock==0?0xffffffff:(uint32_t)time(NULL),coin->usep2sh!=0?0:redeemscript)) == 0 )
printf("error creating tx\n");
else
{
if ( (refT= calloc(1,sizeof(*refT))) == 0 )
return(0);
refT->version = 1;
refT->timestamp = (uint32_t)time(NULL);
strcpy(refT->inputs[0].tx.txidstr,txid);
refT->inputs[0].tx.vout = 0;
refT->numinputs = 1;
strcpy(scriptPubKey,"76a914");
calc_OP_HASH160(scriptPubKey+6,rmd160,mypubkey);
strcat(scriptPubKey,"88ac");
if ( mycoinaddr[0] != 0 )
{
strcpy(refT->outputs[0].coinaddr,mycoinaddr);
strcpy(refT->outputs[0].script,scriptPubKey);
refT->outputs[0].value = funding->destamounts[0] - coin->mgw.txfee;
refT->numoutputs = 1;
if ( lockblocks == 0 )
lockblocks = 10;
refundtx = subatomic_signp2sh(sigstr,coin,refT,1,lockblocks,0,redeemscript,coin->usep2sh,0,0,0,0,0);
free(refT);
} else printf("cant get %s addr from (%s)\n",coin->name,mypubkey);
}
} else printf("error: probably not enough funds\n");
} else printf("error: btc_coinaddr.(%s)\n",mycoinaddr);
free(redeemscript);
} else printf("subatomic_fundingtx: cant create redeemscript\n");
return(refundtx);
}
char *subatomic_spendtx(struct destbuf *spendtxid,char *vintxid,char *refundsig,struct coin777 *coin,char *otherpubkey,char *mypubkey,char *onetimepubkey,uint64_t amount,char *refundtx,char *refredeemscript)
{
char scriptPubKey[128],p2shaddr[64],rmdstr[41],onetimecoinaddr[64],msigcoinaddr[64],sigstr[512]; cJSON *json;
char *redeemscript,*signedtx,*spendtx=0,*mprivkey,*oprivkey; uint8_t rmd160[20]; long diff=0; struct cointx_info *refundT=0;
refundsig[0] = onetimecoinaddr[0] = msigcoinaddr[0] = spendtxid->buf[0] = vintxid[0] = 0;
if ( btc_coinaddr(onetimecoinaddr,coin->addrtype,onetimepubkey) != 0 && btc_coinaddr(msigcoinaddr,coin->addrtype,mypubkey) != 0 )
{
//printf("mypubkey.(%s) -> (%s)\n",mypubkey,msigcoinaddr);
calc_OP_HASH160(rmdstr,rmd160,onetimepubkey);
amount -= coin->mgw.txfee;
coin->ramchain.RTblocknum = _get_RTheight(&coin->ramchain.lastgetinfo,coin->name,coin->serverport,coin->userpass,coin->ramchain.RTblocknum);
if ( (refundT= _decode_rawtransaction(refundtx,coin->mgw.oldtx_format)) != 0 && refundT->inputs[0].sequence != 0xffffffff && refundT->nlocktime != 0 && (diff= ((long)refundT->nlocktime - coin->ramchain.RTblocknum)) > 1 && diff < 1000 )
{
strcpy(vintxid,refundT->inputs[0].tx.txidstr);
if ( (redeemscript= create_atomictx_scripts(coin->p2shtype,scriptPubKey,p2shaddr,otherpubkey,mypubkey,rmdstr)) != 0 )
{
if ( refundT->outputs[0].value == amount && strcmp(refredeemscript,redeemscript) == 0 && refundT->numinputs == 1 && refundT->numoutputs == 1 )
{
if ( (mprivkey= dumpprivkey(coin->name,coin->serverport,coin->userpass,msigcoinaddr)) != 0 && (oprivkey= dumpprivkey(coin->name,coin->serverport,coin->userpass,onetimecoinaddr)) != 0 )
{
//printf("mprivkey.(%s)\n",mprivkey);
if ( (signedtx= subatomic_signp2sh(refundsig,coin,refundT,1,0,0,redeemscript,coin->usep2sh,mprivkey,1,0,0,0)) != 0 )
{
//printf("one sig.(%s)\n",signedtx);
free(signedtx);
strcpy(refundT->outputs[0].coinaddr,onetimecoinaddr);
sprintf(scriptPubKey,"76a914%s88ac",rmdstr);
strcpy(refundT->outputs[0].script,scriptPubKey);
spendtx = subatomic_signp2sh(sigstr,coin,refundT,0,0,0,redeemscript,coin->usep2sh,oprivkey,0,0,0,0);
if ( (json= get_decoderaw_json(coin,spendtx)) != 0 )
{
copy_cJSON(spendtxid,jobj(json,"txid"));
free_json(json);
}
} else printf("Error signing\n");
free(mprivkey);
free(oprivkey);
}
else
{
if ( mprivkey != 0 )
free(mprivkey);
printf("error getting privkeys M.(%s) onetime.(%s)\n",msigcoinaddr,onetimecoinaddr);
}
} else printf("error (%.8f vs %.8f) comparing redeemscript.(%s) vs (%s) io.(%d %d)\n",dstr(refundT->outputs[0].value),dstr(amount),refredeemscript,redeemscript,refundT->numinputs,refundT->numoutputs);
free(redeemscript);
} else printf("error creating redeemscript\n");
free(refundT);
} else printf("error decoding refundT.%p or diff %ld too big (%u %u)\n",refundT,diff,refundT->nlocktime,coin->ramchain.RTblocknum);
} else printf("error getting addresses (%s) (%s)\n",msigcoinaddr,onetimecoinaddr);
return(spendtx);
}
char *subatomic_validate(struct coin777 *coin,char *pubA,char *pubB,char *pkhash,char *refundtx,char *refundsig)
{
char scriptPubKey[512],mycoinaddr[64],p2shaddr[128],mysig[512],*redeemscript,*privkeystr,*signedrefund=0;
struct cointx_info *refundT;
if ( (refundT= _decode_rawtransaction(refundtx,coin->mgw.oldtx_format)) != 0 && btc_coinaddr(mycoinaddr,coin->addrtype,pubA) != 0 )
{
if ( (privkeystr= dumpprivkey(coin->name,coin->serverport,coin->userpass,mycoinaddr)) != 0 )
{
if ( (redeemscript= create_atomictx_scripts(coin->p2shtype,scriptPubKey,p2shaddr,pubA,pubB,pkhash)) != 0 )
{
if ( (signedrefund= subatomic_signp2sh(mysig,coin,refundT,1,0,0,redeemscript,1,privkeystr,0,refundsig,pubB,0)) != 0 )
{
//printf("SIGNEDREFUND.(%s)\n",signedrefund);
}
free(redeemscript);
}
free(privkeystr);
}
free(refundT);
}
return(signedrefund);
}
void test_subatomic()
{
char pkhash[8192],pubA[67],pubB[67],pubP[67]; uint8_t tmpbuf[512]; struct coin777 *coin;
struct subatomic_rawtransaction funding; char refredeemscript[4096],vintxid[128],swapacct[64],othercoinaddr[64],mycoinaddr[64],onetimeaddr[64],refundsig[512],*signedrefund,*refundtx=0,*spendtx=0;
uint64_t amount; struct destbuf pubkey; struct destbuf spendtxid;
coin = coin777_find("BTCD",1);
if ( strcmp(coin->name,"BTC") == 0 )
coin->mgw.oldtx_format = 1;
//coin->usep2sh = 0;
strcpy(mycoinaddr,coin->atomicsend),get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,mycoinaddr), strcpy(pubA,pubkey.buf);
strcpy(othercoinaddr,coin->atomicrecv),get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,othercoinaddr), strcpy(pubB,pubkey.buf);
sprintf(swapacct,"%u",777);
if ( get_acct_coinaddr(onetimeaddr,coin->name,coin->serverport,coin->userpass,swapacct) != 0 )
{
get_pubkey(&pubkey,coin->name,coin->serverport,coin->userpass,onetimeaddr);
strcpy(pubP,pubkey.buf);
printf("onetimeadddr.(%s) pubkey.(%s)\n",onetimeaddr,pubP);
}
calc_OP_HASH160(pkhash,tmpbuf,pubP);
amount = 20000;
printf("pkhash.(%s)\n",pkhash);
if ( (refundtx= subatomic_fundingtx(refredeemscript,&funding,coin,pubA,pubB,pkhash,20000,10)) != 0 )
{
printf("FUNDING.(%s) unsignedrefund.(%s)\n",funding.signedtransaction,refundtx);
if ( (spendtx= subatomic_spendtx(&spendtxid,vintxid,refundsig,coin,pubA,pubB,pubP,amount,refundtx,refredeemscript)) != 0 )
{
printf("vin.%s SPENDTX.(%s) %s refundsig.(%s)\n",vintxid,spendtx,spendtxid.buf,refundsig);
if ( (signedrefund= subatomic_validate(coin,pubA,pubB,pkhash,refundtx,refundsig)) != 0 )
{
printf("SIGNEDREFUND.(%s)\n",signedrefund);
free(signedrefund);
} else printf("null signedrefund\n");
} else printf("null spendtx\n");
free(refundtx);
}
getchar();
}
#endif
#endif