|
|
@ -20,10 +20,14 @@ |
|
|
|
int32_t iguana_vinparse(struct iguana_info *coin,int32_t rwflag,uint8_t *serialized,struct iguana_msgvin *msg) |
|
|
|
{ |
|
|
|
//int32_t sighash,i,plen,len = 0; struct vin_info V; uint32_t sigsize,pubkeysize,p2shsize,suffixlen;
|
|
|
|
int32_t len = 0; |
|
|
|
int32_t p2shlen,len = 0; uint32_t tmp; |
|
|
|
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->prev_hash),msg->prev_hash.bytes); |
|
|
|
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout); |
|
|
|
len += iguana_rwvarint32(rwflag,&serialized[len],&msg->scriptlen); |
|
|
|
if ( rwflag == 1 ) |
|
|
|
tmp = msg->scriptlen; |
|
|
|
len += iguana_rwvarint32(rwflag,&serialized[len],&tmp); |
|
|
|
if ( rwflag == 0 ) |
|
|
|
msg->scriptlen = tmp; |
|
|
|
if ( msg->scriptlen > IGUANA_MAXSCRIPTSIZE ) |
|
|
|
{ |
|
|
|
printf("iguana_vinparse illegal scriptlen.%d\n",msg->scriptlen); |
|
|
@ -36,49 +40,30 @@ int32_t iguana_vinparse(struct iguana_info *coin,int32_t rwflag,uint8_t *seriali |
|
|
|
} |
|
|
|
else if ( msg->vinscript != 0 && msg->scriptlen > 0 ) |
|
|
|
{ |
|
|
|
/*if ( msg->p2shlen > 0 || msg->pubkeys != 0 )
|
|
|
|
memcpy(&serialized[len],msg->vinscript,msg->scriptlen), len += msg->scriptlen; // pubkeys here
|
|
|
|
if ( (p2shlen= msg->p2shlen) > 0 && msg->redeemscript != 0 ) |
|
|
|
{ |
|
|
|
sighash = iguana_vinscriptparse(coin,&V,&sigsize,&pubkeysize,&p2shsize,&suffixlen,msg->vinscript,msg->scriptlen); |
|
|
|
if ( V.numsigs > 0 ) |
|
|
|
{ |
|
|
|
for (i=0; i<V.numsigs; i++) |
|
|
|
{ |
|
|
|
serialized[len++] = V.signers[i].siglen; |
|
|
|
memcpy(&serialized[len],V.signers[i].sig,V.signers[i].siglen); |
|
|
|
} |
|
|
|
} |
|
|
|
if ( msg->pubkeys != 0 && msg->numpubkeys > 0 ) |
|
|
|
{ |
|
|
|
for (i=0; i<msg->numpubkeys; i++) |
|
|
|
{ |
|
|
|
if ( (plen= bitcoin_pubkeylen(V.signers[i].pubkey)) > 0 ) |
|
|
|
{ |
|
|
|
serialized[len++] = plen; |
|
|
|
memcpy(&serialized[len],V.signers[i].pubkey,plen), len += plen; |
|
|
|
} else serialized[len++] = 0; |
|
|
|
} |
|
|
|
} |
|
|
|
if ( msg->p2shlen > 0 && msg->redeemscript != 0 ) |
|
|
|
if ( p2shlen > msg->suffixlen ) |
|
|
|
{ |
|
|
|
if ( msg->p2shlen < 76 ) |
|
|
|
serialized[len++] = msg->p2shlen; |
|
|
|
else if ( msg->p2shlen <= 0xff ) |
|
|
|
p2shlen -= msg->suffixlen; |
|
|
|
if ( p2shlen < 76 ) |
|
|
|
serialized[len++] = p2shlen; |
|
|
|
else if ( p2shlen <= 0xff ) |
|
|
|
{ |
|
|
|
serialized[len++] = 0x4c; |
|
|
|
serialized[len++] = msg->p2shlen; |
|
|
|
serialized[len++] = p2shlen; |
|
|
|
} |
|
|
|
else if ( msg->p2shlen <= 0xffff ) |
|
|
|
else if ( p2shlen <= 0xffff ) |
|
|
|
{ |
|
|
|
serialized[len++] = 0x4d; |
|
|
|
serialized[len++] = (msg->p2shlen & 0xff); |
|
|
|
serialized[len++] = ((msg->p2shlen >> 8) & 0xff); |
|
|
|
serialized[len++] = (p2shlen & 0xff); |
|
|
|
serialized[len++] = ((p2shlen >> 8) & 0xff); |
|
|
|
} else return(-1); |
|
|
|
memcpy(&serialized[len],msg->redeemscript,msg->p2shlen), len += plen; |
|
|
|
memcpy(&serialized[len],msg->redeemscript,p2shlen), len += p2shlen; |
|
|
|
} |
|
|
|
if ( suffixlen > 0 ) |
|
|
|
memcpy(&serialized[len],&msg->vinscript[msg->scriptlen - suffixlen],suffixlen), len += suffixlen; |
|
|
|
} else */ |
|
|
|
memcpy(&serialized[len],msg->vinscript,msg->scriptlen), len += msg->scriptlen; |
|
|
|
if ( msg->suffixlen > 0 ) |
|
|
|
memcpy(&serialized[len],&msg->redeemscript[msg->scriptlen - msg->suffixlen],msg->suffixlen), len += msg->suffixlen; |
|
|
|
} |
|
|
|
} |
|
|
|
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence); |
|
|
|
if ( 0 ) |
|
|
@ -188,19 +173,20 @@ cJSON *iguana_vinjson(struct iguana_info *coin,struct iguana_msgvin *vin) |
|
|
|
iguana_addscript(coin,json,vin->spendscript,vin->spendlen,"scriptPubKey"); |
|
|
|
if ( vin->p2shlen > 0 ) |
|
|
|
iguana_addscript(coin,json,vin->redeemscript,vin->p2shlen,"redeemScript"); |
|
|
|
if ( vin->numpubkeys > 0 ) |
|
|
|
jadd(json,"pubkeys",iguana_pubkeysjson(vin->pubkeys,vin->numpubkeys)); |
|
|
|
} |
|
|
|
return(json); |
|
|
|
} |
|
|
|
|
|
|
|
int32_t iguana_parsevinobj(struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvin *vin,cJSON *vinobj) |
|
|
|
int32_t iguana_parsevinobj(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgvin *vin,cJSON *vinobj,struct vin_info *V) |
|
|
|
{ |
|
|
|
int32_t i,n,plen,len = 0; char *pubkeystr,*hexstr = 0,*redeemstr = 0,*spendstr = 0; cJSON *scriptjson = 0,*obj,*pubkeysjson = 0; |
|
|
|
struct iguana_waddress *waddr; struct iguana_waccount *wacct; int32_t i,n,plen,len = 0; char *suffixstr,*pubkeystr,*hexstr = 0,*redeemstr = 0,*spendstr = 0; cJSON *scriptjson = 0,*obj,*pubkeysjson = 0; |
|
|
|
//printf("PARSEVIN.(%s)\n",jprint(vinobj,0));
|
|
|
|
memset(vin,0,sizeof(*vin)); |
|
|
|
if ( V == 0 ) |
|
|
|
memset(vin,0,sizeof(*vin)); |
|
|
|
vin->prev_vout = -1; |
|
|
|
vin->sequence = juint(vinobj,"sequence"); |
|
|
|
if ( jobj(vinobj,"sequence") != 0 ) |
|
|
|
vin->sequence = juint(vinobj,"sequence"); |
|
|
|
else vin->sequence = 0xffffffff; |
|
|
|
if ( (hexstr= jstr(vinobj,"coinbase")) == 0 ) |
|
|
|
{ |
|
|
|
vin->prev_hash = jbits256(vinobj,"txid"); |
|
|
@ -217,58 +203,78 @@ int32_t iguana_parsevinobj(struct iguana_info *coin,uint8_t *serialized,int32_t |
|
|
|
if ( (obj= jobj(vinobj,"redeemScript")) != 0 ) |
|
|
|
redeemstr = jstr(obj,"hex"); |
|
|
|
} |
|
|
|
/*if ( (addrs= jarray(&n,vinobj,"addresses")) != 0 )
|
|
|
|
} |
|
|
|
if ( hexstr != 0 ) |
|
|
|
{ |
|
|
|
n = (int32_t)strlen(hexstr) >> 1; |
|
|
|
decode_hex(serialized,n,hexstr); |
|
|
|
vin->vinscript = serialized; |
|
|
|
vin->scriptlen = n; |
|
|
|
} //else printf("iguana_parsevinobj: hex script missing (%s)\n",jprint(vinobj,0));
|
|
|
|
if ( V != 0 ) |
|
|
|
{ |
|
|
|
if ( vin->vinscript == 0 ) |
|
|
|
{ |
|
|
|
for (i=0; i<n; i++) |
|
|
|
if ( (V->unspentind= iguana_unspentindfind(coin,V->coinaddr,V->spendscript,&V->spendlen,&V->amount,&V->height,vin->prev_hash,vin->prev_vout,coin->bundlescount-1)) > 0 ) |
|
|
|
{ |
|
|
|
V.signers[i].coinaddr[0] = 0; |
|
|
|
if ( (coinaddr= jstr(jitem(addrs,i),0)) != 0 ) |
|
|
|
safecopy(V.signers[i].coinaddr,coinaddr,sizeof(V.signers[i].coinaddr)); |
|
|
|
if ( V->coinaddr[0] != 0 && (waddr= iguana_waddresssearch(myinfo,coin,&wacct,V->coinaddr)) != 0 ) |
|
|
|
{ |
|
|
|
memcpy(V->signers[0].pubkey,waddr->pubkey,bitcoin_pubkeylen(waddr->pubkey)); |
|
|
|
} |
|
|
|
printf("V %.8f (%s) spendscript.[%d]\n",dstr(V->amount),V->coinaddr,V->spendlen); |
|
|
|
} |
|
|
|
}*/ |
|
|
|
} |
|
|
|
if ( (pubkeysjson= jarray(&n,vinobj,"pubkeys")) != 0 ) |
|
|
|
{ |
|
|
|
if ( vin->vinscript == 0 ) |
|
|
|
{ |
|
|
|
vin->vinscript = serialized; |
|
|
|
vin->vinscript[0] = 0; |
|
|
|
vin->scriptlen = 1; |
|
|
|
} |
|
|
|
for (i=0; i<n; i++) |
|
|
|
{ |
|
|
|
vin->pubkeys[i] = 0; |
|
|
|
if ( (pubkeystr= jstr(jitem(pubkeysjson,i),0)) != 0 && (len= (int32_t)strlen(pubkeystr) >> 1) > 0 ) |
|
|
|
if ( (pubkeystr= jstr(jitem(pubkeysjson,i),0)) != 0 && (plen= (int32_t)strlen(pubkeystr) >> 1) > 0 ) |
|
|
|
{ |
|
|
|
decode_hex(serialized,len,pubkeystr); |
|
|
|
if ( (plen= bitcoin_pubkeylen(serialized)) == len ) |
|
|
|
{ |
|
|
|
vin->pubkeys[i] = serialized; |
|
|
|
//if ( V.signers[i].coinaddr[0] == 0 )
|
|
|
|
// bitcoin_address(V.signers[i].coinaddr,coin->chain->pubtype,serialized,len);
|
|
|
|
serialized = &serialized[len]; |
|
|
|
} |
|
|
|
vin->vinscript[vin->scriptlen++] = plen; |
|
|
|
decode_hex(&vin->vinscript[vin->scriptlen],plen,pubkeystr); |
|
|
|
memcpy(V->signers[i].pubkey,&vin->vinscript[vin->scriptlen],plen); |
|
|
|
vin->scriptlen += plen; |
|
|
|
} |
|
|
|
} |
|
|
|
vin->numpubkeys = n; |
|
|
|
} |
|
|
|
} |
|
|
|
if ( hexstr != 0 ) |
|
|
|
{ |
|
|
|
len = (int32_t)strlen(hexstr) >> 1; |
|
|
|
decode_hex(serialized,len,hexstr); |
|
|
|
vin->vinscript = serialized; |
|
|
|
vin->scriptlen = len; |
|
|
|
serialized = &serialized[len]; |
|
|
|
} //else printf("iguana_parsevinobj: hex script missing (%s)\n",jprint(vinobj,0));
|
|
|
|
if ( spendstr != 0 ) |
|
|
|
{ |
|
|
|
n = (int32_t)strlen(spendstr) >> 1; |
|
|
|
decode_hex(serialized,n,spendstr); |
|
|
|
vin->spendscript = serialized; |
|
|
|
vin->spendlen = n; |
|
|
|
len += n; |
|
|
|
} |
|
|
|
if ( redeemstr != 0 ) |
|
|
|
{ |
|
|
|
n = (int32_t)strlen(redeemstr) >> 1; |
|
|
|
decode_hex(serialized,n,redeemstr); |
|
|
|
vin->redeemscript = serialized; |
|
|
|
vin->p2shlen = n; |
|
|
|
len += n; |
|
|
|
if ( vin->vinscript != 0 ) |
|
|
|
serialized = &vin->vinscript[vin->scriptlen]; |
|
|
|
len = vin->scriptlen; |
|
|
|
if ( redeemstr != 0 ) |
|
|
|
{ |
|
|
|
n = (int32_t)strlen(redeemstr) >> 1; |
|
|
|
decode_hex(serialized,n,redeemstr); |
|
|
|
vin->redeemscript = serialized; |
|
|
|
V->p2shlen = vin->p2shlen = n; |
|
|
|
memcpy(V->p2shscript,serialized,n); |
|
|
|
} |
|
|
|
if ( (suffixstr= jstr(vinobj,"suffix")) != 0 && is_hexstr(suffixstr,(int32_t)strlen(suffixstr)) > 0 ) |
|
|
|
{ |
|
|
|
if ( vin->redeemscript == 0 ) |
|
|
|
{ |
|
|
|
vin->redeemscript = serialized; |
|
|
|
vin->redeemscript[0] = 0; |
|
|
|
} |
|
|
|
n = (int32_t)strlen(suffixstr) >> 1; |
|
|
|
decode_hex(&vin->redeemscript[vin->p2shlen],n,suffixstr); |
|
|
|
vin->p2shlen += n; |
|
|
|
} |
|
|
|
len += vin->p2shlen; |
|
|
|
serialized = vin->redeemscript != 0 ? &vin->redeemscript[vin->p2shlen] : &serialized[len]; |
|
|
|
if ( spendstr != 0 ) |
|
|
|
{ |
|
|
|
n = (int32_t)strlen(spendstr) >> 1; |
|
|
|
decode_hex(serialized,n,spendstr); |
|
|
|
vin->spendscript = serialized; |
|
|
|
vin->spendlen = n; |
|
|
|
} |
|
|
|
len += vin->spendlen; |
|
|
|
} |
|
|
|
return(len); |
|
|
|
} |
|
|
@ -277,7 +283,9 @@ int32_t iguana_parsevoutobj(struct iguana_info *coin,uint8_t *serialized,int32_t |
|
|
|
{ |
|
|
|
int32_t len = 0; cJSON *skey; char *hexstr; |
|
|
|
memset(vout,0,sizeof(*vout)); |
|
|
|
vout->value = jdouble(voutobj,"value") * SATOSHIDEN; |
|
|
|
if ( jobj(voutobj,"satoshis") != 0 ) |
|
|
|
vout->value = j64bits(voutobj,"satoshis"); |
|
|
|
else vout->value = jdouble(voutobj,"value") * SATOSHIDEN; |
|
|
|
if ( (skey= jobj(voutobj,"scriptPubKey")) != 0 ) |
|
|
|
{ |
|
|
|
if ( (hexstr= jstr(skey,"hex")) != 0 ) |
|
|
@ -297,7 +305,7 @@ cJSON *iguana_voutjson(struct iguana_info *coin,struct iguana_msgvout *vout,int3 |
|
|
|
char scriptstr[IGUANA_MAXSCRIPTSIZE+1],asmstr[2*IGUANA_MAXSCRIPTSIZE+1]; int32_t i,m,n,scriptlen,asmtype; struct vin_info *vp; |
|
|
|
uint8_t space[8192]; cJSON *addrs,*skey,*json = cJSON_CreateObject(); |
|
|
|
vp = calloc(1,sizeof(*vp)); |
|
|
|
jaddnum(json,"value",dstr(vout->value)); |
|
|
|
jadd64bits(json,"satoshis",vout->value); |
|
|
|
jaddnum(json,"n",txi); |
|
|
|
//"scriptPubKey":{"asm":"OP_DUP OP_HASH160 5f69cb73016264270dae9f65c51f60d0e4d6fd44 OP_EQUALVERIFY OP_CHECKSIG","reqSigs":1,"type":"pubkeyhash","addresses":["RHyh1V9syARTf2pyxibz7v27D5paBeWza5"]}
|
|
|
|
if ( vout->pk_script != 0 && vout->pk_scriptlen*2+1 < sizeof(scriptstr) ) |
|
|
@ -458,9 +466,12 @@ int32_t iguana_rwmsgtx(struct iguana_info *coin,int32_t rwflag,cJSON *json,uint8 |
|
|
|
return(len); |
|
|
|
} |
|
|
|
|
|
|
|
bits256 iguana_parsetxobj(struct iguana_info *coin,int32_t *txstartp,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,cJSON *txobj) // json -> serialized + (msg,V)
|
|
|
|
bits256 iguana_parsetxobj(struct supernet_info *myinfo,struct iguana_info *coin,int32_t *txstartp,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msg,cJSON *txobj,struct vin_info *V) // json -> serialized + (msg,V)
|
|
|
|
{ |
|
|
|
int32_t i,numvins,numvouts,len = 0; cJSON *array=0; bits256 txid; char vpnstr[64]; |
|
|
|
memset(&txid,0,sizeof(txid)); |
|
|
|
if ( txobj == 0 ) |
|
|
|
return(txid); |
|
|
|
memset(msg,0,sizeof(*msg)); |
|
|
|
vpnstr[0] = 0; |
|
|
|
if ( (msg->version= juint(txobj,"version")) == 0 ) |
|
|
@ -480,7 +491,7 @@ bits256 iguana_parsetxobj(struct iguana_info *coin,int32_t *txstartp,uint8_t *se |
|
|
|
if ( msg->tx_in > 0 && msg->tx_in*sizeof(struct iguana_msgvin) < maxsize ) |
|
|
|
{ |
|
|
|
for (i=0; i<msg->tx_in; i++) |
|
|
|
len += iguana_parsevinobj(coin,&serialized[len],maxsize,&msg->vins[i],jitem(array,i)); |
|
|
|
len += iguana_parsevinobj(myinfo,coin,&serialized[len],maxsize,&msg->vins[i],jitem(array,i),V!=0?&V[i]:0); |
|
|
|
} |
|
|
|
} |
|
|
|
if ( (array= jarray(&numvouts,txobj,"vout")) != 0 ) |
|
|
@ -549,7 +560,7 @@ cJSON *bitcoin_addoutput(struct iguana_info *coin,cJSON *txobj,uint8_t *payments |
|
|
|
char *hexstr; cJSON *item,*skey,*vouts = jduplicate(jobj(txobj,"vout")); |
|
|
|
jdelete(txobj,"vout"); |
|
|
|
item = cJSON_CreateObject(); |
|
|
|
jaddnum(item,"value",dstr(satoshis)); |
|
|
|
jadd64bits(item,"satoshis",satoshis); |
|
|
|
skey = cJSON_CreateObject(); |
|
|
|
hexstr = malloc(len*2 + 1); |
|
|
|
init_hexbytes_noT(hexstr,paymentscript,len); |
|
|
@ -592,11 +603,16 @@ cJSON *bitcoin_addinput(struct iguana_info *coin,cJSON *txobj,bits256 txid,int32 |
|
|
|
return(txobj); |
|
|
|
} |
|
|
|
|
|
|
|
char *bitcoin_json2hex(struct iguana_info *coin,bits256 *txidp,cJSON *txjson) |
|
|
|
char *bitcoin_json2hex(struct supernet_info *myinfo,struct iguana_info *coin,bits256 *txidp,cJSON *txjson,struct vin_info *V) |
|
|
|
{ |
|
|
|
int32_t txstart; uint8_t *serialized; struct iguana_msgtx msgtx; char *txbytes = 0; |
|
|
|
if ( txjson == 0 ) |
|
|
|
{ |
|
|
|
memset(txidp,0,sizeof(*txidp)); |
|
|
|
return(0); |
|
|
|
} |
|
|
|
serialized = malloc(IGUANA_MAXPACKETSIZE*1.5); |
|
|
|
*txidp = iguana_parsetxobj(coin,&txstart,serialized,IGUANA_MAXPACKETSIZE*1.5,&msgtx,txjson); |
|
|
|
*txidp = iguana_parsetxobj(myinfo,coin,&txstart,serialized,IGUANA_MAXPACKETSIZE*1.5,&msgtx,txjson,V); |
|
|
|
if ( msgtx.allocsize > 0 ) |
|
|
|
{ |
|
|
|
txbytes = malloc(msgtx.allocsize*2 + 1); |
|
|
@ -630,112 +646,151 @@ cJSON *bitcoin_hex2json(struct iguana_info *coin,bits256 *txidp,struct iguana_ms |
|
|
|
return(txobj); |
|
|
|
} |
|
|
|
|
|
|
|
int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t numinputs,int32_t sighashsingle) |
|
|
|
bits256 bitcoin_sigtxid(struct iguana_info *coin,uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,int32_t vini,uint8_t *spendscript,int32_t spendlen,int32_t hashtype,char *vpnstr) |
|
|
|
{ |
|
|
|
bits256 txid,sigtxid,revsigtxid; uint8_t *sig,*pubkey; struct vin_info *vp; |
|
|
|
char txidstr[128],bigstr[2560],coinaddr[64],vpnstr[64],str[65]; uint32_t suffixlen,sigsize,pubkeysize; |
|
|
|
int32_t savelen,n2,i,j,k,plen,vini=0,flag,hashtype,retval,siglen,asmtype,numvouts; |
|
|
|
numvouts = msgtx->tx_out; |
|
|
|
vpnstr[0] = 0; |
|
|
|
*signedtx = 0; |
|
|
|
memset(signedtxidp,0,sizeof(*signedtxidp)); |
|
|
|
retval = -numinputs; |
|
|
|
for (vini=0; vini<numinputs; vini++) |
|
|
|
int32_t i,len; bits256 sigtxid,txid,revsigtxid; struct iguana_msgtx dest; |
|
|
|
dest = *msgtx; |
|
|
|
memset(sigtxid.bytes,0,sizeof(sigtxid)); |
|
|
|
if ( hashtype != SIGHASH_ALL ) |
|
|
|
{ |
|
|
|
printf("currently only SIGHASH_ALL supported, not %d\n",hashtype); |
|
|
|
return(sigtxid); |
|
|
|
} |
|
|
|
for (i=0; i<msgtx->tx_in; i++) |
|
|
|
{ |
|
|
|
if ( i == vini ) |
|
|
|
{ |
|
|
|
dest.vins[i].vinscript = spendscript; |
|
|
|
dest.vins[i].scriptlen = spendlen; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
dest.vins[i].vinscript = (uint8_t *)""; |
|
|
|
dest.vins[i].scriptlen = 0; |
|
|
|
} |
|
|
|
dest.vins[i].p2shlen = 0; |
|
|
|
dest.vins[i].redeemscript = 0; |
|
|
|
} |
|
|
|
len = iguana_rwmsgtx(coin,1,0,serialized,maxlen,&dest,&txid,vpnstr); |
|
|
|
if ( len > 0 ) |
|
|
|
{ |
|
|
|
len += iguana_rwnum(1,&serialized[len],sizeof(hashtype),&hashtype); |
|
|
|
revsigtxid = bits256_doublesha256(0,serialized,len); |
|
|
|
for (i=0; i<sizeof(revsigtxid); i++) |
|
|
|
sigtxid.bytes[31-i] = revsigtxid.bytes[i]; |
|
|
|
} |
|
|
|
return(sigtxid); |
|
|
|
} |
|
|
|
|
|
|
|
int32_t iguana_msgtx_Vset(struct iguana_info *coin,uint8_t *serialized,int32_t maxlen,struct iguana_msgtx *msgtx,struct vin_info *V) |
|
|
|
{ |
|
|
|
int32_t vini,j,scriptlen,p2shlen,siglen,plen,len = 0; uint8_t *script; struct vin_info *vp; |
|
|
|
for (vini=0; vini<msgtx->tx_in; vini++) |
|
|
|
{ |
|
|
|
//saveinput = msgtx->vins[vini].vinscript;
|
|
|
|
vp = &V[vini]; |
|
|
|
sig = &msgtx->vins[vini].vinscript[1]; |
|
|
|
siglen = msgtx->vins[vini].vinscript[0]; |
|
|
|
vp->vin = msgtx->vins[vini]; |
|
|
|
flag = 0; |
|
|
|
for (k=0; k<2; k++) |
|
|
|
{ |
|
|
|
asmtype = (k == 0) ? IGUANA_SCRIPT_76A988AC : IGUANA_SCRIPT_76AC; |
|
|
|
savelen = vp->spendlen; |
|
|
|
if ( bitcoin_scriptget(coin,&hashtype,&sigsize,&pubkeysize,&suffixlen,vp,msgtx->vins[vini].vinscript,msgtx->vins[vini].scriptlen,asmtype) < 0 ) |
|
|
|
msgtx->vins[vini].vinscript = script = &serialized[len]; |
|
|
|
msgtx->vins[vini].vinscript[0] = 0; |
|
|
|
scriptlen = 0; |
|
|
|
for (j=0; j<vp->N; j++) |
|
|
|
{ |
|
|
|
if ( (siglen= vp->signers[j].siglen) > 0 ) |
|
|
|
{ |
|
|
|
script[scriptlen++] = siglen; |
|
|
|
memcpy(&script[scriptlen],vp->signers[j].sig,siglen); |
|
|
|
scriptlen += siglen; |
|
|
|
} |
|
|
|
} |
|
|
|
for (j=0; j<vp->N; j++) |
|
|
|
{ |
|
|
|
if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) > 0 ) |
|
|
|
{ |
|
|
|
script[scriptlen++] = plen; |
|
|
|
memcpy(&script[scriptlen],vp->signers[j].pubkey,plen); |
|
|
|
scriptlen += plen; |
|
|
|
} |
|
|
|
} |
|
|
|
msgtx->vins[vini].scriptlen = scriptlen; |
|
|
|
if ( vp->p2shscript != 0 && (p2shlen= vp->p2shlen) > 0 ) |
|
|
|
{ |
|
|
|
msgtx->vins[vini].redeemscript = &script[scriptlen]; |
|
|
|
if ( p2shlen < 76 ) |
|
|
|
script[scriptlen++] = p2shlen; |
|
|
|
else if ( p2shlen <= 0xff ) |
|
|
|
{ |
|
|
|
printf("cant get script for (%s).v%d\n",bits256_str(str,vp->vin.prev_hash),vp->vin.prev_vout); |
|
|
|
continue; |
|
|
|
script[scriptlen++] = 0x4c; |
|
|
|
script[scriptlen++] = p2shlen; |
|
|
|
} |
|
|
|
if ( vp->spendlen == 0 ) |
|
|
|
vp->spendlen = savelen; |
|
|
|
if ( sighashsingle != 0 && vini == 0 ) |
|
|
|
else if ( p2shlen <= 0xffff ) |
|
|
|
{ |
|
|
|
msgtx->tx_out = 1; |
|
|
|
hashtype = SIGHASH_SINGLE; |
|
|
|
} else msgtx->tx_out = numvouts; |
|
|
|
msgtx->vins[vini].spendscript = vp->spendscript; |
|
|
|
msgtx->vins[vini].spendlen = vp->spendlen; |
|
|
|
msgtx->vins[vini].sequence = vp->sequence; |
|
|
|
printf("spendscript.[%d]\n",vp->spendlen); |
|
|
|
script[scriptlen++] = 0x4d; |
|
|
|
script[scriptlen++] = (p2shlen & 0xff); |
|
|
|
script[scriptlen++] = ((p2shlen >> 8) & 0xff); |
|
|
|
} else return(-1); |
|
|
|
memcpy(&script[scriptlen],vp->p2shscript,p2shlen), scriptlen += p2shlen; |
|
|
|
if ( (msgtx->vins[vini].suffixlen= vp->suffixlen) > 0 ) |
|
|
|
{ |
|
|
|
memcpy(&script[scriptlen],&vp->p2shscript[vp->p2shlen - vp->suffixlen],vp->suffixlen); |
|
|
|
scriptlen += vp->suffixlen; |
|
|
|
} |
|
|
|
} |
|
|
|
len += scriptlen; |
|
|
|
} |
|
|
|
return(len); |
|
|
|
} |
|
|
|
|
|
|
|
int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxlen,struct vin_info *V,int32_t sighash) |
|
|
|
{ |
|
|
|
bits256 sigtxid; uint8_t *sig; struct vin_info *vp; char vpnstr[64]; int32_t plen,i,j,vini=0,flag=0,siglen,numvouts; |
|
|
|
numvouts = msgtx->tx_out; |
|
|
|
vpnstr[0] = 0; |
|
|
|
*signedtx = 0; |
|
|
|
memset(signedtxidp,0,sizeof(*signedtxidp)); |
|
|
|
for (vini=0; vini<msgtx->tx_in; vini++) |
|
|
|
{ |
|
|
|
sigtxid = bitcoin_sigtxid(coin,serialized,maxlen,msgtx,vini,msgtx->vins[vini].spendscript,msgtx->vins[vini].spendlen,sighash,vpnstr); |
|
|
|
if ( bits256_nonz(sigtxid) != 0 ) |
|
|
|
{ |
|
|
|
vp = &V[vini]; |
|
|
|
for (j=0; j<vp->N; j++) |
|
|
|
{ |
|
|
|
pubkey = vp->signers[j].pubkey; |
|
|
|
if ( (plen= bitcoin_pubkeylen(pubkey)) < 0 ) |
|
|
|
sig = vp->signers[j].sig; |
|
|
|
siglen = vp->signers[j].siglen; |
|
|
|
if ( bits256_nonz(vp->signers[j].privkey) != 0 ) |
|
|
|
{ |
|
|
|
if ( bits256_nonz(vp->signers[j].privkey) > 0 ) |
|
|
|
{ |
|
|
|
pubkey = vp->signers[j].pubkey; |
|
|
|
bitcoin_pubkey33(coin->ctx,pubkey,vp->signers[j].privkey); |
|
|
|
plen = bitcoin_pubkeylen(pubkey); |
|
|
|
} |
|
|
|
if ( plen < 0 ) |
|
|
|
{ |
|
|
|
printf("nopubkey for j.%d vini.%d plen.%d [%02x]\n",j,vini,plen,pubkey[0]); |
|
|
|
continue; |
|
|
|
} |
|
|
|
siglen = bitcoin_sign(coin->ctx,sig,sigtxid,vp->signers[j].privkey); |
|
|
|
if ( (plen= bitcoin_pubkeylen(vp->signers[j].pubkey)) <= 0 ) |
|
|
|
bitcoin_pubkey33(coin->ctx,vp->signers[j].pubkey,vp->signers[j].privkey); |
|
|
|
sig[siglen++] = sighash; |
|
|
|
vp->signers[j].siglen = siglen; |
|
|
|
for (i=0; i<siglen; i++) |
|
|
|
printf("%02x",sig[i]); |
|
|
|
// s2 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1;
|
|
|
|
printf(" SIGNEDTX.[%02x] siglen.%d\n",sig[siglen-1],siglen); |
|
|
|
} |
|
|
|
bitcoin_address(coinaddr,coin->chain->pubtype,pubkey,plen); |
|
|
|
n2 = iguana_rwmsgtx(coin,1,0,serialized,maxsize,msgtx,&txid,vpnstr); |
|
|
|
if ( n2 > 0 ) |
|
|
|
if ( sig == 0 || siglen == 0 ) |
|
|
|
{ |
|
|
|
n2 += iguana_rwnum(1,&serialized[n2],sizeof(hashtype),&hashtype); |
|
|
|
//printf("hashtype.%d [%02x]\n",hashtype,sig[siglen-1]);
|
|
|
|
revsigtxid = bits256_doublesha256(txidstr,serialized,n2); |
|
|
|
for (i=0; i<sizeof(revsigtxid); i++) |
|
|
|
sigtxid.bytes[31-i] = revsigtxid.bytes[i]; |
|
|
|
if ( 1 && bits256_nonz(vp->signers[j].privkey) != 0 ) |
|
|
|
{ |
|
|
|
siglen = bitcoin_sign(coin->ctx,vp->signers[j].sig,sigtxid,vp->signers[j].privkey); |
|
|
|
sig = vp->signers[j].sig; |
|
|
|
sig[siglen++] = hashtype; |
|
|
|
vp->signers[j].siglen = siglen; |
|
|
|
msgtx->vins[vini].vinscript = calloc(1,siglen*2+256); // fix this memleak!
|
|
|
|
msgtx->vins[vini].scriptlen = bitcoin_scriptsig(coin,msgtx->vins[vini].vinscript,0,(const struct vin_info *)vp,msgtx); |
|
|
|
for (i=0; i<siglen; i++) |
|
|
|
printf("%02x",sig[i]); |
|
|
|
// s2 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1;
|
|
|
|
printf(" SIGNEDTX.[%02x] plen.%d siglen.%d\n",sig[siglen-1],plen,siglen); |
|
|
|
} |
|
|
|
if ( bitcoin_verify(coin->ctx,sig,vp->signers[j].siglen-1,sigtxid,vp->signers[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) |
|
|
|
{ |
|
|
|
init_hexbytes_noT(bigstr,serialized,n2); |
|
|
|
printf("(%s) doesnt verify hash2.%s\n",bigstr,bits256_str(str,sigtxid)); |
|
|
|
*signedtx = iguana_rawtxbytes(coin,0,msgtx); |
|
|
|
*signedtxidp = msgtx->txid; |
|
|
|
printf("SIG.%d ERROR %s\n",vini,*signedtx); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
cJSON *txobj = cJSON_CreateObject(); |
|
|
|
*signedtx = iguana_rawtxbytes(coin,txobj,msgtx); |
|
|
|
*signedtxidp = msgtx->txid; |
|
|
|
printf("SIG.%d VERIFIED \n",vini);//%s (%s)\n",vini,*signedtx,jprint(txobj,1));
|
|
|
|
flag = 1; |
|
|
|
break; |
|
|
|
} |
|
|
|
} else printf("bitcoin_verifyvins: vini.%d n2.%d\n",vini,n2); |
|
|
|
} |
|
|
|
if ( flag > 0 ) |
|
|
|
{ |
|
|
|
retval++; |
|
|
|
break; |
|
|
|
memset(vp->signers[j].pubkey,0,sizeof(vp->signers[j].pubkey)); |
|
|
|
continue; |
|
|
|
} |
|
|
|
if ( bitcoin_verify(coin->ctx,sig,siglen-1,sigtxid,vp->signers[j].pubkey,bitcoin_pubkeylen(vp->signers[j].pubkey)) < 0 ) |
|
|
|
{ |
|
|
|
|
|
|
|
printf("SIG.%d.%d ERROR\n",vini,j); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
printf("SIG.%d.%d VERIFIED \n",vini,j);//%s (%s)\n",vini,*signedtx,jprint(txobj,1));
|
|
|
|
flag++; |
|
|
|
} |
|
|
|
} |
|
|
|
if ( vp->type != IGUANA_SCRIPT_76A988AC && vp->type != IGUANA_SCRIPT_76AC ) |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
return(retval); |
|
|
|
iguana_msgtx_Vset(coin,serialized,maxlen,msgtx,V); |
|
|
|
cJSON *txobj = cJSON_CreateObject(); |
|
|
|
*signedtx = iguana_rawtxbytes(coin,txobj,msgtx); |
|
|
|
//printf("SIGNEDTX.(%s)\n",jprint(txobj,1));
|
|
|
|
*signedtxidp = msgtx->txid; |
|
|
|
return(flag); |
|
|
|
} |
|
|
|
|
|
|
|
int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,char *rawtxstr,struct vin_info *V,int32_t numinputs) |
|
|
@ -749,9 +804,9 @@ int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **si |
|
|
|
vpnstr[0] = 0; |
|
|
|
decode_hex(serialized,len,rawtxstr); |
|
|
|
memset(&msgtx,0,sizeof(msgtx)); |
|
|
|
if ( iguana_rwmsgtx(coin,0,0,serialized,maxsize,&msgtx,&txid,vpnstr) > 0 ) |
|
|
|
if ( iguana_rwmsgtx(coin,0,0,serialized,maxsize,&msgtx,&txid,vpnstr) > 0 && numinputs == msgtx.tx_in ) |
|
|
|
{ |
|
|
|
if ( bitcoin_verifyvins(coin,signedtxidp,signedtx,&msgtx,serialized2,maxsize,V,numinputs,0) == 0 ) |
|
|
|
if ( bitcoin_verifyvins(coin,signedtxidp,signedtx,&msgtx,serialized2,maxsize,V,SIGHASH_ALL) == 0 ) |
|
|
|
retval = 0; |
|
|
|
else printf("bitcoin_verifytx: bitcoin_verifyvins error\n"); |
|
|
|
} else printf("bitcoin_verifytx: error iguana_rwmsgtx\n"); |
|
|
@ -791,7 +846,7 @@ cJSON *iguana_signtx(struct supernet_info *myinfo,struct iguana_info *coin,bits2 |
|
|
|
} |
|
|
|
else vitem = 0; |
|
|
|
vp->N = vp->M = 1; |
|
|
|
if ( (rawtxstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 ) |
|
|
|
if ( (rawtxstr= bitcoin_json2hex(myinfo,coin,&txid,txobj,0)) != 0 ) |
|
|
|
{ |
|
|
|
for (j=0; j<sizeof(spend->inputs[i].privkeys)/sizeof(*spend->inputs[i].privkeys); j++) |
|
|
|
{ |
|
|
@ -817,10 +872,10 @@ cJSON *iguana_signtx(struct supernet_info *myinfo,struct iguana_info *coin,bits2 |
|
|
|
} |
|
|
|
} |
|
|
|
/*if ( spend->inputs[i].spendlen > 0 )
|
|
|
|
{ |
|
|
|
memcpy(vp->spendscript,spend->inputs[i].spendscript,spend->inputs[i].spendlen); |
|
|
|
vp->spendlen = spend->inputs[i].spendlen; |
|
|
|
}*/ |
|
|
|
{ |
|
|
|
memcpy(vp->spendscript,spend->inputs[i].spendscript,spend->inputs[i].spendlen); |
|
|
|
vp->spendlen = spend->inputs[i].spendlen; |
|
|
|
}*/ |
|
|
|
if ( spend->inputs[i].p2shlen > 0 ) |
|
|
|
{ |
|
|
|
memcpy(vp->p2shscript,spend->inputs[i].p2shscript,spend->inputs[i].p2shlen); |
|
|
@ -857,8 +912,85 @@ cJSON *iguana_signtx(struct supernet_info *myinfo,struct iguana_info *coin,bits2 |
|
|
|
return(txobj); |
|
|
|
} |
|
|
|
|
|
|
|
#include "../includes/iguana_apidefs.h" |
|
|
|
#include "../includes/iguana_apideclares.h" |
|
|
|
int32_t iguana_vininfo_create(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *serialized,int32_t maxsize,struct iguana_msgtx *msgtx,cJSON *vins,int32_t numinputs,struct vin_info *V) |
|
|
|
{ |
|
|
|
int32_t i,plen,len = 0; struct vin_info *vp; struct iguana_waccount *wacct; struct iguana_waddress *waddr; uint32_t sigsize,pubkeysize,p2shsize,suffixlen; |
|
|
|
msgtx->tx_in = numinputs; |
|
|
|
maxsize -= (sizeof(struct iguana_msgvin) * msgtx->tx_in); |
|
|
|
msgtx->vins = (struct iguana_msgvin *)&serialized[maxsize]; |
|
|
|
if ( msgtx->tx_in > 0 && msgtx->tx_in*sizeof(struct iguana_msgvin) < maxsize ) |
|
|
|
{ |
|
|
|
for (i=0; i<msgtx->tx_in; i++) |
|
|
|
{ |
|
|
|
vp = &V[i]; |
|
|
|
len += iguana_parsevinobj(myinfo,coin,&serialized[len],maxsize,&msgtx->vins[i],jitem(vins,i),vp); |
|
|
|
if ( msgtx->vins[i].spendscript == 0 ) |
|
|
|
{ |
|
|
|
if ( (vp->unspentind= iguana_unspentindfind(coin,vp->coinaddr,vp->spendscript,&vp->spendlen,&vp->amount,&vp->height,msgtx->vins[i].prev_hash,msgtx->vins[i].prev_vout,coin->bundlescount-1)) > 0 ) |
|
|
|
{ |
|
|
|
msgtx->vins[i].spendscript = vp->spendscript; |
|
|
|
msgtx->vins[i].spendlen = vp->spendlen; |
|
|
|
vp->hashtype = iguana_vinscriptparse(coin,V,&sigsize,&pubkeysize,&p2shsize,&suffixlen,vp->spendscript,vp->spendlen); |
|
|
|
vp->suffixlen = suffixlen; |
|
|
|
printf("V %.8f (%s) spendscript.[%d]\n",dstr(vp->amount),vp->coinaddr,vp->spendlen); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
memcpy(vp->spendscript,msgtx->vins[i].spendscript,msgtx->vins[i].spendlen); |
|
|
|
vp->spendlen = msgtx->vins[i].spendlen; |
|
|
|
_iguana_calcrmd160(coin,vp); |
|
|
|
if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) > 0 ) |
|
|
|
bitcoin_address(vp->coinaddr,coin->chain->pubtype,vp->signers[0].pubkey,plen); |
|
|
|
} |
|
|
|
if ( vp->coinaddr[i] != 0 && (waddr= iguana_waddresssearch(myinfo,coin,&wacct,vp->coinaddr)) != 0 ) |
|
|
|
{ |
|
|
|
vp->signers[0].privkey = waddr->privkey; |
|
|
|
if ( bitcoin_pubkeylen(waddr->pubkey) != vp->spendscript[1] || vp->spendscript[vp->spendlen-1] != 0xac ) |
|
|
|
memcpy(vp->signers[0].pubkey,waddr->pubkey,bitcoin_pubkeylen(waddr->pubkey)); |
|
|
|
} |
|
|
|
if ( vp->M == 0 && vp->N == 0 ) |
|
|
|
vp->M = vp->N = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
/*for (i=0; i<msgtx->tx_out; i++)
|
|
|
|
{ |
|
|
|
if ( msgtx->vouts[i].pk_script != 0 ) |
|
|
|
{ |
|
|
|
for (j=0; j<msgtx->vouts[i].pk_scriptlen; j++) |
|
|
|
printf("%02x",msgtx->vouts[i].pk_script[j]); |
|
|
|
printf(" pk_script[%d]\n",i); |
|
|
|
} |
|
|
|
}*/ |
|
|
|
return(len); |
|
|
|
} |
|
|
|
|
|
|
|
void iguana_ensure_privkey(struct supernet_info *myinfo,struct iguana_info *coin,bits256 privkey) |
|
|
|
{ |
|
|
|
uint8_t pubkey33[33]; struct iguana_waccount *wacct; struct iguana_waddress *waddr,addr; char coinaddr[128]; |
|
|
|
bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); |
|
|
|
bitcoin_address(coinaddr,coin->chain->pubtype,pubkey33,33); |
|
|
|
//printf("privkey for (%s)\n",coinaddr);
|
|
|
|
if ( myinfo->expiration != 0 && ((waddr= iguana_waddresssearch(myinfo,coin,&wacct,coinaddr)) == 0 || bits256_nonz(waddr->privkey) == 0) ) |
|
|
|
{ |
|
|
|
if ( waddr == 0 ) |
|
|
|
{ |
|
|
|
memset(&addr,0,sizeof(addr)); |
|
|
|
iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&addr,privkey); |
|
|
|
if ( (wacct= iguana_waccountfind(myinfo,coin,"default")) != 0 ) |
|
|
|
waddr = iguana_waddressadd(myinfo,coin,wacct,&addr,0); |
|
|
|
} |
|
|
|
if ( waddr != 0 ) |
|
|
|
{ |
|
|
|
waddr->privkey = privkey; |
|
|
|
if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->chain->wiftype) > 0 ) |
|
|
|
{ |
|
|
|
waddr->wiftype = coin->chain->wiftype; |
|
|
|
waddr->addrtype = coin->chain->pubtype; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
char *_setVsigner(struct iguana_info *coin,struct vin_info *V,int32_t ind,char *pubstr,char *wifstr) |
|
|
|
{ |
|
|
@ -870,18 +1002,22 @@ char *_setVsigner(struct iguana_info *coin,struct vin_info *V,int32_t ind,char * |
|
|
|
else return(0); |
|
|
|
} |
|
|
|
|
|
|
|
int32_t bitcoin_txaddspend(struct iguana_info *coin,cJSON *txobj,char *destaddress,double destamount) |
|
|
|
int32_t bitcoin_txaddspend(struct iguana_info *coin,cJSON *txobj,char *destaddress,uint64_t satoshis) |
|
|
|
{ |
|
|
|
uint8_t outputscript[128],addrtype,rmd160[20]; int32_t scriptlen; |
|
|
|
if ( bitcoin_validaddress(coin,destaddress) == 0 && destamount > 0. ) |
|
|
|
if ( bitcoin_validaddress(coin,destaddress) == 0 && satoshis != 0 ) |
|
|
|
{ |
|
|
|
bitcoin_addr2rmd160(&addrtype,rmd160,destaddress); |
|
|
|
scriptlen = bitcoin_standardspend(outputscript,0,rmd160); |
|
|
|
bitcoin_addoutput(coin,txobj,outputscript,scriptlen,destamount * SATOSHIDEN); |
|
|
|
bitcoin_addoutput(coin,txobj,outputscript,scriptlen,satoshis); |
|
|
|
return(0); |
|
|
|
} else return(-1); |
|
|
|
} |
|
|
|
|
|
|
|
#include "../includes/iguana_apidefs.h" |
|
|
|
#include "../includes/iguana_apideclares.h" |
|
|
|
|
|
|
|
|
|
|
|
P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount,destaddress2,destamount2,M,N,pubA,wifA,pubB,wifB,pubC,wifC) |
|
|
|
{ |
|
|
|
struct vin_info V; uint8_t p2sh_rmd160[20],serialized[2096],spendscript[32],pubkeys[3][65],*pubkeyptrs[3]; int32_t spendlen; |
|
|
@ -899,9 +1035,9 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount |
|
|
|
memset(&V,0,sizeof(V)); |
|
|
|
txobj = bitcoin_createtx(active,0); |
|
|
|
if ( destaddress[0] != 0 && destamount > 0. ) |
|
|
|
bitcoin_txaddspend(active,txobj,destaddress,destamount); |
|
|
|
bitcoin_txaddspend(active,txobj,destaddress,destamount * SATOSHIDEN); |
|
|
|
if ( destaddress2[0] != 0 && destamount2 > 0. ) |
|
|
|
bitcoin_txaddspend(active,txobj,destaddress2,destamount2); |
|
|
|
bitcoin_txaddspend(active,txobj,destaddress2,destamount2 * SATOSHIDEN); |
|
|
|
if ( pubA[0] != 0 && (retstr= _setVsigner(active,&V,0,pubA,wifA)) != 0 ) |
|
|
|
return(retstr); |
|
|
|
if ( N >= 2 && pubB[0] != 0 && (retstr= _setVsigner(active,&V,1,pubB,wifB)) != 0 ) |
|
|
@ -929,7 +1065,7 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount |
|
|
|
bitcoin_addinput(active,txobj,vintxid,vinvout,0xffffffff,spendscript,spendlen,V.p2shscript,V.p2shlen,pubkeyptrs,N); |
|
|
|
bitcoin_address(msigaddr,active->chain->p2shtype,V.p2shscript,V.p2shlen); |
|
|
|
retjson = cJSON_CreateObject(); |
|
|
|
if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,&msgtx,serialized,sizeof(serialized),&V,1,0) == 0 ) |
|
|
|
if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,&msgtx,serialized,sizeof(serialized),&V,SIGHASH_ALL) == 0 ) |
|
|
|
{ |
|
|
|
jaddstr(retjson,"result","msigtx"); |
|
|
|
if ( signedtx != 0 ) |
|
|
@ -942,66 +1078,85 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount |
|
|
|
|
|
|
|
STRING_ARRAY_OBJ_STRING(bitcoinrpc,signrawtransaction,rawtx,vins,privkeys,sighash) |
|
|
|
{ |
|
|
|
bits256 txid; uint8_t pubkey33[33]; struct iguana_waccount *wacct; struct iguana_waddress *waddr,addr; char *privkeystr,coinaddr[128],*signedtx = 0; bits256 privkey; int32_t i,n,numinputs = 1; struct bitcoin_spend *spend; cJSON *txobj=0,*item,*retjson = cJSON_CreateObject(); |
|
|
|
char *privkeystr,*signedtx = 0; struct vin_info *V; bits256 txid,signedtxid,privkey; int32_t len,i,n,maxsize,numinputs = 1; uint8_t *serialized=0,*serialized2=0,*serialized3=0; struct iguana_msgtx msgtx; cJSON *txobj,*item,*retjson; int uselessbitcoin_error = 0; |
|
|
|
retjson = cJSON_CreateObject(); |
|
|
|
if ( remoteaddr != 0 ) |
|
|
|
return(clonestr("{\"error\":\"no remote\"}")); |
|
|
|
if ( myinfo->expiration == 0 ) |
|
|
|
return(clonestr("{\"error\":\"need to unlock wallet\"}")); |
|
|
|
//printf("rawtx.(%s) vins.(%s) privkeys.(%s) sighash.(%s)\n",rawtx,jprint(vins,0),jprint(privkeys,0),sighash);
|
|
|
|
//printf("rawtx.(%s) vins.(%s) privkeys.(%s) sighash.(%s)\n",rawtx,jprint(vins,0),jprint(privkeys,0),sighash);
|
|
|
|
if ( sighash == 0 || sighash[0] == 0 ) |
|
|
|
sighash = "ALL"; |
|
|
|
if ( strcmp(sighash,"ALL") != 0 ) |
|
|
|
jaddstr(retjson,"error","only sighash all supported for now"); |
|
|
|
else |
|
|
|
jaddstr(retjson,"error","only sighash all (ALL) supported for now"); |
|
|
|
maxsize = 65536; |
|
|
|
if ( rawtx != 0 && rawtx[0] != 0 && (len= (int32_t)strlen(rawtx)>>1) < maxsize ) |
|
|
|
{ |
|
|
|
signedtx = clonestr(rawtx); |
|
|
|
if ( (numinputs= cJSON_GetArraySize(vins)) > 0 && (n= cJSON_GetArraySize(privkeys)) > 0 ) |
|
|
|
serialized = malloc(maxsize); |
|
|
|
serialized2 = malloc(maxsize); |
|
|
|
serialized3 = malloc(maxsize); |
|
|
|
memset(&msgtx,0,sizeof(msgtx)); |
|
|
|
decode_hex(serialized,len,rawtx); |
|
|
|
if ( (txobj= bitcoin_hex2json(coin,&txid,&msgtx,rawtx)) != 0 ) |
|
|
|
{ |
|
|
|
spend = calloc(1,sizeof(*spend) + (sizeof(*spend->inputs) * numinputs)); |
|
|
|
spend->numinputs = numinputs; |
|
|
|
for (i=0; i<n; i++) |
|
|
|
char *checkstr; |
|
|
|
//printf("txobj.(%s)\n",jprint(txobj,0));
|
|
|
|
if ( (checkstr= bitcoin_json2hex(myinfo,coin,&txid,txobj,0)) != 0 ) |
|
|
|
{ |
|
|
|
item = jitem(privkeys,i); |
|
|
|
privkeystr = jstr(item,0); |
|
|
|
privkey = iguana_str2priv(myinfo,coin,privkeystr); |
|
|
|
spend->inputs[i].sequence = 0xffffffff; |
|
|
|
spend->inputs[i].privkeys[0] = privkey; |
|
|
|
if ( bits256_nonz(privkey) != 0 ) |
|
|
|
if ( strcmp(rawtx,checkstr) != 0 ) |
|
|
|
{ |
|
|
|
bitcoin_pubkey33(myinfo->ctx,pubkey33,privkey); |
|
|
|
memcpy(spend->inputs[i].pubkeys[0],pubkey33,33); |
|
|
|
bitcoin_address(coinaddr,coin->chain->pubtype,pubkey33,33); |
|
|
|
if ( myinfo->expiration != 0 && ((waddr= iguana_waddresssearch(myinfo,coin,&wacct,coinaddr)) == 0 || bits256_nonz(waddr->privkey) == 0) ) |
|
|
|
{ |
|
|
|
if ( waddr == 0 ) |
|
|
|
{ |
|
|
|
memset(&addr,0,sizeof(addr)); |
|
|
|
iguana_waddresscalc(coin->chain->pubtype,coin->chain->wiftype,&addr,privkey); |
|
|
|
if ( (wacct= iguana_waccountfind(myinfo,coin,"default")) != 0 ) |
|
|
|
waddr = iguana_waddressadd(myinfo,coin,wacct,&addr,0); |
|
|
|
} |
|
|
|
if ( waddr != 0 ) |
|
|
|
{ |
|
|
|
waddr->privkey = privkey; |
|
|
|
if ( bitcoin_priv2wif(waddr->wifstr,waddr->privkey,coin->chain->wiftype) > 0 ) |
|
|
|
{ |
|
|
|
waddr->wiftype = coin->chain->wiftype; |
|
|
|
waddr->addrtype = coin->chain->pubtype; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
printf("RAW.(%s) ->\nNEW.(%s)\n",rawtx,checkstr); |
|
|
|
free_json(txobj); |
|
|
|
free(checkstr); |
|
|
|
free(serialized); |
|
|
|
free(serialized2); |
|
|
|
free(serialized3); |
|
|
|
jaddstr(retjson,"error",uselessbitcoin_error != 0 ? "-22" : "hex2json -> json2hex error"); |
|
|
|
return(jprint(retjson,1)); |
|
|
|
} |
|
|
|
free(checkstr); |
|
|
|
} |
|
|
|
txobj = iguana_signtx(myinfo,coin,&txid,&signedtx,spend,txobj,vins); |
|
|
|
free(spend); |
|
|
|
free_json(txobj); |
|
|
|
} |
|
|
|
if ( (numinputs= cJSON_GetArraySize(vins)) > 0 ) |
|
|
|
V = calloc(numinputs,sizeof(*V)); |
|
|
|
memset(&msgtx,0,sizeof(msgtx)); |
|
|
|
if ( iguana_rwmsgtx(coin,0,0,serialized,maxsize,&msgtx,&txid,"") > 0 && numinputs == msgtx.tx_in ) |
|
|
|
{ |
|
|
|
if ( (n= cJSON_GetArraySize(privkeys)) > 0 ) |
|
|
|
{ |
|
|
|
for (i=0; i<n; i++) |
|
|
|
{ |
|
|
|
item = jitem(privkeys,i); |
|
|
|
privkeystr = jstr(item,0); |
|
|
|
privkey = iguana_str2priv(myinfo,coin,privkeystr); |
|
|
|
if ( bits256_nonz(privkey) != 0 ) |
|
|
|
iguana_ensure_privkey(myinfo,coin,privkey); |
|
|
|
} |
|
|
|
} |
|
|
|
signedtx = 0; |
|
|
|
iguana_vininfo_create(myinfo,coin,serialized2,maxsize,&msgtx,vins,numinputs,V); |
|
|
|
bitcoin_verifyvins(coin,&signedtxid,&signedtx,&msgtx,serialized3,maxsize,V,SIGHASH_ALL); |
|
|
|
free(V); |
|
|
|
if ( signedtx != 0 ) |
|
|
|
{ |
|
|
|
jaddstr(retjson,"result",signedtx); |
|
|
|
free(signedtx); |
|
|
|
} |
|
|
|
} else jaddstr(retjson,"error",uselessbitcoin_error != 0 ? "-22" : "no transaction from verifyvins"); |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
/*char *testscript = "76a914010966776006953d5567439e5e39f86a0d273bee88ac";
|
|
|
|
uint8_t script[256]; bits256 sigtxid; int32_t scriptlen = (int32_t)strlen(testscript) >> 1; |
|
|
|
decode_hex(script,scriptlen,testscript); |
|
|
|
sigtxid = bitcoin_sigtxid(coin,serialized,sizeof(serialized),&msgtx,0,msgtx.vins[0].spendscript,msgtx.vins[0].spendlen,SIGHASH_ALL,""); |
|
|
|
char str[65]; printf("sigtxid.(%s)\n",bits256_str(str,sigtxid));*/ |
|
|
|
jaddstr(retjson,"error",uselessbitcoin_error != 0 ? "-22" : "couldnt load serialized tx or mismatched numinputs"); |
|
|
|
} |
|
|
|
free(serialized); |
|
|
|
free(serialized2); |
|
|
|
free(serialized3); |
|
|
|
} else jaddstr(retjson,"error",uselessbitcoin_error != 0 ? "-22" : "no rawtx or rawtx too big"); |
|
|
|
return(jprint(retjson,1)); |
|
|
|
} |
|
|
|
|
|
|
|