From 0cbacc1d4fb7f9287214814433339b6c9a5b3401 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 Feb 2016 15:54:39 -0300 Subject: [PATCH] connect atomic to rpc --- crypto777/bitcoind_RPC.c | 4 +- crypto777/iguana_utils.c | 2 +- iguana/SuperNET.h | 7 +- iguana/exchanges/bitcoin.c | 673 +++++++++++++++++++++++++++++----- iguana/exchanges/bitcoin.h | 7 +- iguana/iguana777.h | 7 +- iguana/iguana_instantdex.c | 24 +- iguana/iguana_msg.c | 4 +- iguana/iguana_pubkeys.c | 4 +- iguana/iguana_ramchain.c | 2 +- iguana/iguana_tx.c | 105 ------ iguana/swaps/iguana_BTCswap.c | 40 +- 12 files changed, 648 insertions(+), 231 deletions(-) diff --git a/crypto777/bitcoind_RPC.c b/crypto777/bitcoind_RPC.c index 248fd3c8a..f1bfff35e 100755 --- a/crypto777/bitcoind_RPC.c +++ b/crypto777/bitcoind_RPC.c @@ -49,7 +49,7 @@ char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char * long i,j,len; char *retstr = 0; cJSON *json,*result,*error; - printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); + //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) { printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); @@ -163,7 +163,7 @@ try_again: databuf = (char *)malloc(256 + strlen(command) + strlen(params)); sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); - printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); + //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); // } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); curl_easy_setopt(curl_handle,CURLOPT_POST,1L); diff --git a/crypto777/iguana_utils.c b/crypto777/iguana_utils.c index 18a4e2a2d..d69a4e981 100755 --- a/crypto777/iguana_utils.c +++ b/crypto777/iguana_utils.c @@ -342,7 +342,7 @@ int32_t decode_hex(unsigned char *bytes,int32_t n,char *hex) int32_t init_hexbytes_noT(char *hexbytes,unsigned char *message,long len) { int32_t i; - if ( len == 0 ) + if ( len <= 0 ) { hexbytes[0] = 0; return(1); diff --git a/iguana/SuperNET.h b/iguana/SuperNET.h index 308f7ad82..0ec56a56f 100644 --- a/iguana/SuperNET.h +++ b/iguana/SuperNET.h @@ -122,7 +122,12 @@ struct category_msg { struct queueitem DL; struct tai t; uint64_t remoteipbits; struct exchange_quote { uint64_t satoshis,orderid,offerNXT,exchangebits; double price,volume; uint32_t timestamp,val; }; -struct bitcoin_unspent { bits256 txid,privkeys[16]; uint64_t value; int32_t vout; uint8_t addrtype,rmd160[20],script[512]; }; +struct bitcoin_unspent +{ + bits256 txid,privkeys[16]; uint64_t value; int32_t vout,spendlen; uint32_t sequence; + uint8_t addrtype,rmd160[20],spendscript[2048]; +}; + struct bitcoin_spend { char changeaddr[64]; diff --git a/iguana/exchanges/bitcoin.c b/iguana/exchanges/bitcoin.c index 402b3d78c..f877c4dbb 100755 --- a/iguana/exchanges/bitcoin.c +++ b/iguana/exchanges/bitcoin.c @@ -31,6 +31,290 @@ static const char base58_chars[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijk #define IGUANA_SCRIPT_DATA 11 #define IGUANA_SCRIPT_STRANGE 15 +enum opcodetype +{ + // push value + OP_0 = 0x00, + OP_FALSE = OP_0, + OP_PUSHDATA1 = 0x4c, + OP_PUSHDATA2 = 0x4d, + OP_PUSHDATA4 = 0x4e, + OP_1NEGATE = 0x4f, + OP_RESERVED = 0x50, + OP_1 = 0x51, + OP_TRUE=OP_1, + OP_2 = 0x52, + OP_3 = 0x53, + OP_4 = 0x54, + OP_5 = 0x55, + OP_6 = 0x56, + OP_7 = 0x57, + OP_8 = 0x58, + OP_9 = 0x59, + OP_10 = 0x5a, + OP_11 = 0x5b, + OP_12 = 0x5c, + OP_13 = 0x5d, + OP_14 = 0x5e, + OP_15 = 0x5f, + OP_16 = 0x60, + + // control + OP_NOP = 0x61, + OP_VER = 0x62, + OP_IF = 0x63, + OP_NOTIF = 0x64, + OP_VERIF = 0x65, + OP_VERNOTIF = 0x66, + OP_ELSE = 0x67, + OP_ENDIF = 0x68, + OP_VERIFY = 0x69, + OP_RETURN = 0x6a, + + // stack ops + OP_TOALTSTACK = 0x6b, + OP_FROMALTSTACK = 0x6c, + OP_2DROP = 0x6d, + OP_2DUP = 0x6e, + OP_3DUP = 0x6f, + OP_2OVER = 0x70, + OP_2ROT = 0x71, + OP_2SWAP = 0x72, + OP_IFDUP = 0x73, + OP_DEPTH = 0x74, + OP_DROP = 0x75, + OP_DUP = 0x76, + OP_NIP = 0x77, + OP_OVER = 0x78, + OP_PICK = 0x79, + OP_ROLL = 0x7a, + OP_ROT = 0x7b, + OP_SWAP = 0x7c, + OP_TUCK = 0x7d, + + // splice ops + OP_CAT = 0x7e, + OP_SUBSTR = 0x7f, + OP_LEFT = 0x80, + OP_RIGHT = 0x81, + OP_SIZE = 0x82, + + // bit logic + OP_INVERT = 0x83, + OP_AND = 0x84, + OP_OR = 0x85, + OP_XOR = 0x86, + OP_EQUAL = 0x87, + OP_EQUALVERIFY = 0x88, + OP_RESERVED1 = 0x89, + OP_RESERVED2 = 0x8a, + + // numeric + OP_1ADD = 0x8b, + OP_1SUB = 0x8c, + OP_2MUL = 0x8d, + OP_2DIV = 0x8e, + OP_NEGATE = 0x8f, + OP_ABS = 0x90, + OP_NOT = 0x91, + OP_0NOTEQUAL = 0x92, + + OP_ADD = 0x93, + OP_SUB = 0x94, + OP_MUL = 0x95, + OP_DIV = 0x96, + OP_MOD = 0x97, + OP_LSHIFT = 0x98, + OP_RSHIFT = 0x99, + + OP_BOOLAND = 0x9a, + OP_BOOLOR = 0x9b, + OP_NUMEQUAL = 0x9c, + OP_NUMEQUALVERIFY = 0x9d, + OP_NUMNOTEQUAL = 0x9e, + OP_LESSTHAN = 0x9f, + OP_GREATERTHAN = 0xa0, + OP_LESSTHANOREQUAL = 0xa1, + OP_GREATERTHANOREQUAL = 0xa2, + OP_MIN = 0xa3, + OP_MAX = 0xa4, + + OP_WITHIN = 0xa5, + + // crypto + OP_RIPEMD160 = 0xa6, + OP_SHA1 = 0xa7, + OP_SHA256 = 0xa8, + OP_HASH160 = 0xa9, + OP_HASH256 = 0xaa, + OP_CODESEPARATOR = 0xab, + OP_CHECKSIG = 0xac, + OP_CHECKSIGVERIFY = 0xad, + OP_CHECKMULTISIG = 0xae, + OP_CHECKMULTISIGVERIFY = 0xaf, + + // expansion + OP_NOP1 = 0xb0, + OP_NOP2 = 0xb1, + OP_NOP3 = 0xb2, + OP_NOP4 = 0xb3, + OP_NOP5 = 0xb4, + OP_NOP6 = 0xb5, + OP_NOP7 = 0xb6, + OP_NOP8 = 0xb7, + OP_NOP9 = 0xb8, + OP_NOP10 = 0xb9, + + // template matching params + OP_SMALLINTEGER = 0xfa, + OP_PUBKEYS = 0xfb, + OP_PUBKEYHASH = 0xfd, + OP_PUBKEY = 0xfe, + + OP_INVALIDOPCODE = 0xff, +}; + +const char *get_opname(int32_t *extralenp,enum opcodetype opcode) +{ + *extralenp = 0; + switch (opcode) + { + // push value + case OP_0 : return "0"; + case OP_PUSHDATA1 : *extralenp = 1; return "OP_PUSHDATA1"; + case OP_PUSHDATA2 : *extralenp = 2; return "OP_PUSHDATA2"; + case OP_PUSHDATA4 : *extralenp = 4; return "OP_PUSHDATA4"; + case OP_1NEGATE : return "-1"; + case OP_RESERVED : return "OP_RESERVED"; + case OP_1 : return "1"; + case OP_2 : return "2"; + case OP_3 : return "3"; + case OP_4 : return "4"; + case OP_5 : return "5"; + case OP_6 : return "6"; + case OP_7 : return "7"; + case OP_8 : return "8"; + case OP_9 : return "9"; + case OP_10 : return "10"; + case OP_11 : return "11"; + case OP_12 : return "12"; + case OP_13 : return "13"; + case OP_14 : return "14"; + case OP_15 : return "15"; + case OP_16 : return "16"; + + // control + case OP_NOP : return "OP_NOP"; + case OP_VER : return "OP_VER"; + case OP_IF : return "OP_IF"; + case OP_NOTIF : return "OP_NOTIF"; + case OP_VERIF : return "OP_VERIF"; + case OP_VERNOTIF : return "OP_VERNOTIF"; + case OP_ELSE : return "OP_ELSE"; + case OP_ENDIF : return "OP_ENDIF"; + case OP_VERIFY : return "OP_VERIFY"; + case OP_RETURN : return "OP_RETURN"; + + // stack ops + case OP_TOALTSTACK : return "OP_TOALTSTACK"; + case OP_FROMALTSTACK : return "OP_FROMALTSTACK"; + case OP_2DROP : return "OP_2DROP"; + case OP_2DUP : return "OP_2DUP"; + case OP_3DUP : return "OP_3DUP"; + case OP_2OVER : return "OP_2OVER"; + case OP_2ROT : return "OP_2ROT"; + case OP_2SWAP : return "OP_2SWAP"; + case OP_IFDUP : return "OP_IFDUP"; + case OP_DEPTH : return "OP_DEPTH"; + case OP_DROP : return "OP_DROP"; + case OP_DUP : return "OP_DUP"; + case OP_NIP : return "OP_NIP"; + case OP_OVER : return "OP_OVER"; + case OP_PICK : return "OP_PICK"; + case OP_ROLL : return "OP_ROLL"; + case OP_ROT : return "OP_ROT"; + case OP_SWAP : return "OP_SWAP"; + case OP_TUCK : return "OP_TUCK"; + + // splice ops + case OP_CAT : return "OP_CAT"; + case OP_SUBSTR : return "OP_SUBSTR"; + case OP_LEFT : return "OP_LEFT"; + case OP_RIGHT : return "OP_RIGHT"; + case OP_SIZE : return "OP_SIZE"; + + // bit logic + case OP_INVERT : return "OP_INVERT"; + case OP_AND : return "OP_AND"; + case OP_OR : return "OP_OR"; + case OP_XOR : return "OP_XOR"; + case OP_EQUAL : return "OP_EQUAL"; + case OP_EQUALVERIFY : return "OP_EQUALVERIFY"; + case OP_RESERVED1 : return "OP_RESERVED1"; + case OP_RESERVED2 : return "OP_RESERVED2"; + + // numeric + case OP_1ADD : return "OP_1ADD"; + case OP_1SUB : return "OP_1SUB"; + case OP_2MUL : return "OP_2MUL"; + case OP_2DIV : return "OP_2DIV"; + case OP_NEGATE : return "OP_NEGATE"; + case OP_ABS : return "OP_ABS"; + case OP_NOT : return "OP_NOT"; + case OP_0NOTEQUAL : return "OP_0NOTEQUAL"; + case OP_ADD : return "OP_ADD"; + case OP_SUB : return "OP_SUB"; + case OP_MUL : return "OP_MUL"; + case OP_DIV : return "OP_DIV"; + case OP_MOD : return "OP_MOD"; + case OP_LSHIFT : return "OP_LSHIFT"; + case OP_RSHIFT : return "OP_RSHIFT"; + case OP_BOOLAND : return "OP_BOOLAND"; + case OP_BOOLOR : return "OP_BOOLOR"; + case OP_NUMEQUAL : return "OP_NUMEQUAL"; + case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY"; + case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL"; + case OP_LESSTHAN : return "OP_LESSTHAN"; + case OP_GREATERTHAN : return "OP_GREATERTHAN"; + case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL"; + case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL"; + case OP_MIN : return "OP_MIN"; + case OP_MAX : return "OP_MAX"; + case OP_WITHIN : return "OP_WITHIN"; + + // crypto + case OP_RIPEMD160 : return "OP_RIPEMD160"; + case OP_SHA1 : return "OP_SHA1"; + case OP_SHA256 : return "OP_SHA256"; + case OP_HASH160 : return "OP_HASH160"; + case OP_HASH256 : return "OP_HASH256"; + case OP_CODESEPARATOR : return "OP_CODESEPARATOR"; + case OP_CHECKSIG : return "OP_CHECKSIG"; + case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY"; + case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG"; + case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; + + // expanson + case OP_NOP1 : return "OP_NOP1"; + case OP_NOP2 : return "OP_NOP2"; + case OP_NOP3 : return "OP_NOP3"; + case OP_NOP4 : return "OP_NOP4"; + case OP_NOP5 : return "OP_NOP5"; + case OP_NOP6 : return "OP_NOP6"; + case OP_NOP7 : return "OP_NOP7"; + case OP_NOP8 : return "OP_NOP8"; + case OP_NOP9 : return "OP_NOP9"; + case OP_NOP10 : return "OP_NOP10"; + + case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE"; + // Note: + // The template matching params OP_SMALLDATA/etc are defined in opcodetype enum + // as kind of implementation hack, they are *NOT* real opcodes. If found in real + // Script, just let the default: case deal with them. + default: return "OP_UNKNOWN"; + } +} + char *bitcoind_passthru(char *coinstr,char *serverport,char *userpass,char *method,char *params) { return(bitcoind_RPC(0,coinstr,serverport,userpass,method,params)); @@ -326,6 +610,8 @@ int32_t bitcoin_sign(uint8_t *sig,int32_t maxlen,uint8_t *data,int32_t datalen,b int32_t bitcoin_verify(uint8_t *sig,int32_t siglen,uint8_t *data,int32_t datalen,EC_KEY *KEY,uint8_t *pubkey,int32_t len) { ECDSA_SIG *esig; int32_t retval = -1; uint8_t tmp[33],*ptr,*sigptr = sig; EC_KEY *origkey = KEY; + if ( len < 0 ) + return(-1); if ( (esig= ECDSA_SIG_new()) != 0 ) { if ( d2i_ECDSA_SIG(&esig,(const uint8_t **)&sigptr,siglen) != 0 ) @@ -402,8 +688,8 @@ int32_t bitcoin_standardspend(uint8_t *script,int32_t n,uint8_t rmd160[20]) int32_t bitcoin_checklocktimeverify(uint8_t *script,int32_t n,uint32_t locktime) { script[n++] = (locktime >> 24), script[n++] = (locktime >> 16), script[n++] = (locktime >> 8), script[n++] = locktime; - script[n++] = OP_CHECKLOCKTIMEVERIFY; - script[n++] = OP_DROP; + script[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY; + script[n++] = SCRIPT_OP_DROP; return(n); } @@ -510,8 +796,9 @@ int32_t bitcoin_cltvscript(uint8_t p2shtype,char *ps2h_coinaddr,uint8_t p2sh_rmd int32_t iguana_scriptgen(struct iguana_info *coin,int32_t *Mp,int32_t *nump,char *coinaddr,uint8_t *script,char *asmstr,uint8_t rmd160[20],uint8_t type,const struct vin_info *vp,int32_t txi) { - uint8_t addrtype; char rmd160str[41],pubkeystr[256]; int32_t i,m,n,flag = 0,scriptlen = 0; + uint8_t addrtype; char rmd160str[41],pubkeystr[256]; int32_t plen,i,m,n,flag = 0,scriptlen = 0; m = n = 1; + asmstr[0] = 0; if ( type == IGUANA_SCRIPT_76A988AC || type == IGUANA_SCRIPT_76AC || type == IGUANA_SCRIPT_P2SH ) { if ( type == IGUANA_SCRIPT_P2SH ) @@ -528,10 +815,12 @@ int32_t iguana_scriptgen(struct iguana_info *coin,int32_t *Mp,int32_t *nump,char coinaddr[0] = 0; break; case IGUANA_SCRIPT_76AC: - init_hexbytes_noT(pubkeystr,(uint8_t *)vp->signers[0].pubkey,bitcoin_pubkeylen(vp->signers[0].pubkey)); + if ( (plen= bitcoin_pubkeylen(vp->signers[0].pubkey)) < 0 ) + return(0); + init_hexbytes_noT(pubkeystr,(uint8_t *)vp->signers[0].pubkey,plen); sprintf(asmstr,"OP_DUP %s OP_CHECKSIG // %s",pubkeystr,coinaddr); scriptlen = bitcoin_pubkeyspend(script,0,(uint8_t *)vp->signers[0].pubkey); - //printf("[%02x] scriptlen.%d (%s)\n",vp->signers[0].pubkey[0],scriptlen,asmstr); + printf("[%02x] scriptlen.%d (%s)\n",vp->signers[0].pubkey[0],scriptlen,asmstr); break; case IGUANA_SCRIPT_76A988AC: sprintf(asmstr,"OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG // %s",rmd160str,coinaddr); @@ -567,8 +856,11 @@ int32_t iguana_scriptgen(struct iguana_info *coin,int32_t *Mp,int32_t *nump,char sprintf(asmstr,"%d ",m); for (i=0; isigners[i].pubkey,bitcoin_pubkeylen(vp->signers[i].pubkey)); - strcat(asmstr," "); + if ( (plen= bitcoin_pubkeylen(vp->signers[i].pubkey)) > 0 ) + { + init_hexbytes_noT(asmstr + strlen(asmstr),(uint8_t *)vp->signers[i].pubkey,plen); + strcat(asmstr," "); + } else strcat(asmstr,"NOPUBKEY "); } sprintf(asmstr + strlen(asmstr),"%d // M.%d of N.%d [",n,m,n); for (i=0; iprev_vout = -1; vin->sequence = juint(vinobj,"sequence"); @@ -755,20 +1053,26 @@ int32_t iguana_parsevinobj(struct iguana_info *coin,uint8_t *serialized,int32_t { vin->prev_hash = jbits256(vinobj,"txid"); vin->prev_vout = jint(vinobj,"vout"); - if ( (sigjson= jobj(vinobj,"scriptSig")) != 0 ) - hexstr = jstr(sigjson,"hex"); + if ( (scriptjson= jobj(vinobj,"scriptSig")) != 0 ) + hexstr = jstr(scriptjson,"hex"); + if ( (scriptjson= jobj(vinobj,"scriptPub")) != 0 ) + spendstr = jstr(scriptjson,"hex"); } if ( hexstr != 0 ) { len = (int32_t)strlen(hexstr) >> 1; decode_hex(serialized,len,hexstr); - vin->script = serialized; + vin->sigscript = serialized; vin->scriptlen = len; - } - else + serialized = &serialized[len]; + } //else printf("iguana_parsevinobj: hex script missing (%s)\n",jprint(vinobj,0)); + if ( spendstr != 0 ) { - printf("iguana_parsevinobj: hex script missing (%s)\n",jprint(vinobj,0)); - return(0); + n = (int32_t)strlen(spendstr) >> 1; + decode_hex(serialized,n,spendstr); + vin->spendscript = serialized; + vin->spendlen = n; + len += n; } return(len); } @@ -821,22 +1125,43 @@ cJSON *iguana_voutjson(struct iguana_info *coin,struct iguana_msgvout *vout,int3 return(json); } +void iguana_addscript(struct iguana_info *coin,cJSON *dest,uint8_t *script,int32_t scriptlen,char *fieldname) +{ + char *scriptstr,scriptbuf[8192+256]; int32_t len; cJSON *scriptobj; + if ( scriptlen > sizeof(scriptbuf) ) + len = (scriptlen << 1) + 256, scriptstr = malloc(len); + else scriptstr = scriptbuf, len = sizeof(scriptbuf); + init_hexbytes_noT(scriptstr,script,scriptlen); + if ( strcmp(fieldname,"coinbase") == 0 ) + jaddstr(dest,"coinbase",scriptstr); + else + { + scriptobj = cJSON_CreateObject(); + jaddstr(scriptobj,"hex",scriptstr); + iguana_expandscript(coin,scriptstr,len,script,scriptlen); + if ( scriptstr[0] != 0 ) + jaddstr(scriptobj,"asm",scriptstr); + if ( scriptstr != scriptbuf ) + free(scriptstr); + jadd(dest,fieldname,scriptobj); + } +} + cJSON *iguana_vinjson(struct iguana_info *coin,struct iguana_msgvin *vin) { - char scriptstr[8192+1],str[65]; int32_t vout; cJSON *sigjson,*json = cJSON_CreateObject(); + char str[65]; int32_t vout; cJSON *json = cJSON_CreateObject(); vout = vin->prev_vout; jaddnum(json,"sequence",vin->sequence); - if ( vin->script != 0 && vin->scriptlen*2+1 < sizeof(scriptstr) ) - init_hexbytes_noT(scriptstr,vin->script,vin->scriptlen); if ( vout < 0 && bits256_nonz(vin->prev_hash) == 0 ) - jaddstr(json,"coinbase",scriptstr); + iguana_addscript(coin,json,vin->sigscript,vin->scriptlen,"coinbase"); else { jaddstr(json,"txid",bits256_str(str,vin->prev_hash)); jaddnum(json,"vout",vout); - sigjson = cJSON_CreateObject(); - jaddstr(sigjson,"hex",scriptstr); - jadd(json,"scriptSig",sigjson); + if ( vin->scriptlen > 0 ) + iguana_addscript(coin,json,vin->sigscript,vin->scriptlen,"scriptSig"); + if ( vin->spendlen > 0 ) + iguana_addscript(coin,json,vin->spendscript,vin->spendlen,"scriptPub"); } return(json); } @@ -848,16 +1173,16 @@ int32_t iguana_vinparse(struct iguana_info *coin,int32_t rwflag,uint8_t *seriali len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout); len += iguana_rwvarint32(rwflag,&serialized[len],&msg->scriptlen); if ( rwflag == 0 ) - msg->script = &serialized[len]; - else memcpy(&serialized[len],msg->script,msg->scriptlen); + msg->sigscript = &serialized[len]; + else memcpy(&serialized[len],msg->sigscript,msg->scriptlen); len += msg->scriptlen; len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence); if ( 0 ) { int32_t i; char str[65]; for (i=0; iscriptlen; i++) - printf("%02x",msg->script[i]); - printf(" prev_hash.(%s) vout.%d [%p] scriptlen.%d rwflag.%d\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->script,msg->scriptlen,rwflag); + printf("%02x",msg->sigscript[i]); + printf(" prev_hash.(%s) vout.%d [%p] scriptlen.%d rwflag.%d\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->sigscript,msg->scriptlen,rwflag); } return(len); } @@ -907,6 +1232,7 @@ int32_t iguana_rwmsgtx(struct iguana_info *coin,int32_t rwflag,cJSON *json,uint8 return(-1); maxsize -= (sizeof(struct iguana_msgvin) * msg->tx_in); msg->vins = (struct iguana_msgvin *)&serialized[maxsize]; + memset(msg->vins,0,sizeof(struct iguana_msgvin) * msg->tx_in); } //printf("tx_in.%08x\n",msg->tx_in); if ( msg->tx_in > 0 && msg->tx_in*sizeof(struct iguana_msgvin) < maxsize ) @@ -1097,11 +1423,12 @@ int32_t bitcoin_scriptget(struct iguana_info *coin,int32_t *hashtypep,struct vin return(vp->spendlen); } -int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,int32_t *scriptlens,struct iguana_msgtx *msgtx,uint8_t *serialized,int32_t maxsize,struct vin_info *V,int32_t sighashsingle) +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 sighashsingle) { - bits256 txid,sigtxid,revsigtxid; char txidstr[128],bigstr[2560],coinaddr[64],vpnstr[64],str[65]; - uint8_t *sig,*pubkey,*saveinput; struct vin_info *vp; - int32_t n2,i,j,k,plen,vini=0,flag,numvins,hashtype,retval,siglen,asmtype,numvouts = msgtx->tx_out; + bits256 txid,sigtxid,revsigtxid; uint8_t *sig,*pubkey; struct vin_info *vp; + char txidstr[128],bigstr[2560],coinaddr[64],vpnstr[64],str[65]; + int32_t n2,i,j,k,plen,vini=0,flag,numvins,hashtype,retval,siglen,asmtype,numvouts; + numvouts = msgtx->tx_out; vpnstr[0] = 0; *signedtx = 0; memset(signedtxidp,0,sizeof(*signedtxidp)); @@ -1109,18 +1436,18 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** retval = -numvins; for (vini=0; vinivins[vini].script; + //saveinput = msgtx->vins[vini].sigscript; vp = &V[vini]; - for (i=0; ivins[i].scriptlen = 0; - sig = &msgtx->vins[vini].script[1]; - siglen = msgtx->vins[vini].script[0]; + //for (i=0; ivins[i].spendlen = 0; + sig = &msgtx->vins[vini].sigscript[1]; + siglen = msgtx->vins[vini].sigscript[0]; vp->vin = msgtx->vins[vini]; flag = 0; for (k=0; k<2; k++) { asmtype = (k == 0) ? IGUANA_SCRIPT_76A988AC : IGUANA_SCRIPT_76AC; - if ( bitcoin_scriptget(coin,&hashtype,vp,saveinput,scriptlens[vini],asmtype) < 0 ) + if ( bitcoin_scriptget(coin,&hashtype,vp,msgtx->vins[vini].sigscript,msgtx->vins[vini].scriptlen,asmtype) < 0 ) { printf("cant get script for (%s).v%d\n",bits256_str(str,vp->vin.prev_hash),vp->vin.prev_vout); continue; @@ -1130,19 +1457,29 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** msgtx->tx_out = 1; hashtype = SIGHASH_SINGLE; } else msgtx->tx_out = numvouts; - msgtx->vins[vini].script = vp->spendscript; - msgtx->vins[vini].scriptlen = vp->spendlen; + msgtx->vins[vini].spendscript = vp->spendscript; + msgtx->vins[vini].spendlen = vp->spendlen; + msgtx->vins[vini].sequence = vp->sequence; for (j=0; jN; j++) { pubkey = vp->signers[j].pubkey; if ( (plen= bitcoin_pubkeylen(pubkey)) < 0 ) { - printf("illegal plen.%d [%02x]\n",plen,pubkey[0]); - break; + if ( bits256_nonz(vp->signers[j].privkey) > 0 ) + { + pubkey = vp->signers[j].pubkey; + bitcoin_pubkey33(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; + } } bitcoin_address(coinaddr,coin->chain->pubtype,pubkey,plen); n2 = iguana_rwmsgtx(coin,1,0,serialized,maxsize,msgtx,&txid,vpnstr); - msgtx->vins[vini].script = saveinput; + //msgtx->vins[vini].script = saveinput; if ( n2 > 0 ) { n2 += iguana_rwnum(1,&serialized[n2],sizeof(hashtype),&hashtype); @@ -1156,7 +1493,7 @@ int32_t bitcoin_verifyvins(struct iguana_info *coin,bits256 *signedtxidp,char ** sig = vp->signers[j].sig; sig[vp->signers[j].siglen++] = hashtype; siglen = vp->signers[j].siglen; - msgtx->vins[vini].scriptlen = bitcoin_scriptsig(msgtx->vins[vini].script,0,(const struct vin_info *)vp); + msgtx->vins[vini].scriptlen = bitcoin_scriptsig(msgtx->vins[vini].sigscript,0,(const struct vin_info *)vp); for (i=0; i>= 1; vpnstr[0] = 0; decode_hex(serialized,len,rawtxstr); @@ -1218,15 +1539,9 @@ int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **si if ( iguana_rwmsgtx(coin,0,0,serialized,maxsize,&msgtx,&txid,vpnstr) > 0 ) { numvins = msgtx.tx_in; - scriptlens = calloc(numvins,sizeof(*scriptlens)); - for (i=0; i 0 ) { txbytes = malloc(msgtx.allocsize*2 + 1); init_hexbytes_noT(txbytes,&serialized[txstart],msgtx.allocsize); - } else printf("bitcoin_txtest: zero msgtx allocsize\n"); + } else printf("bitcoin_txtest: zero msgtx allocsize.(%s)\n",jprint(txjson,0)); free(serialized); return(txbytes); } @@ -1293,6 +1608,7 @@ cJSON *bitcoin_createtx(struct iguana_info *coin,int32_t locktime) cJSON *bitcoin_addoutput(struct iguana_info *coin,cJSON *txobj,uint8_t *paymentscript,int32_t len,uint64_t satoshis) { char *hexstr; cJSON *item,*skey,*vouts = jduplicate(jobj(txobj,"vout")); + jdelete(txobj,"vout"); item = cJSON_CreateObject(); jaddnum(item,"value",dstr(satoshis)); skey = cJSON_CreateObject(); @@ -1301,23 +1617,152 @@ cJSON *bitcoin_addoutput(struct iguana_info *coin,cJSON *txobj,uint8_t *payments jaddstr(skey,"hex",hexstr); free(hexstr); jadd(item,"scriptPubkey",skey); - jdelete(vouts,"vout"); - jadd(vouts,"vout",item); + jaddi(vouts,item); + jadd(txobj,"vout",vouts); + ///printf("addoutput.(%s %s)\n",hexstr,jprint(skey,0)); return(txobj); } -cJSON *bitcoin_addinput(struct iguana_info *coin,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequence) +cJSON *bitcoin_addinput(struct iguana_info *coin,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequence,uint8_t *script,int32_t scriptlen) { - cJSON *item,*vins = jduplicate(jobj(txobj,"vin")); + cJSON *item,*vins; + vins = jduplicate(jobj(txobj,"vin")); + jdelete(txobj,"vin"); item = cJSON_CreateObject(); + iguana_addscript(coin,item,script,scriptlen,"scriptPubKey"); jaddbits256(item,"txid",txid); jaddnum(item,"vout",vout); jaddnum(item,"sequence",sequence); - jdelete(vins,"vin"); - jadd(vins,"vin",item); + jaddi(vins,item); + jadd(txobj,"vin",vins); + printf("addvin -> (%s)\n",jprint(txobj,0)); + return(txobj); +} + +struct bitcoin_unspent *iguana_bestfit(struct iguana_info *coin,struct bitcoin_unspent *unspents,int32_t numunspents,uint64_t value,int32_t mode) +{ + int32_t i; uint64_t above,below,gap,atx_value; struct bitcoin_unspent *vin,*abovevin,*belowvin; + abovevin = belowvin = 0; + for (above=below=i=0; ivalue; + //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); +} + +struct bitcoin_spend *iguana_spendset(struct supernet_info *myinfo,struct iguana_info *coin,int64_t amount,int64_t txfee,char *account) +{ + int32_t i,mode,numunspents,maxinputs = 1024; struct bitcoin_unspent *ptr,*up; + struct bitcoin_unspent *ups; struct bitcoin_spend *spend; double balance; int64_t remains; + if ( (ups= iguana_unspentsget(myinfo,coin,0,&balance,&numunspents,coin->chain->minconfirms,account)) == 0 ) + return(0); + spend = calloc(1,sizeof(*spend) + sizeof(*spend->inputs) * maxinputs); + spend->txfee = txfee; + remains = txfee + amount; + spend->satoshis = remains; + ptr = spend->inputs; + for (i=0; i=0; mode--) + if ( (up= iguana_bestfit(coin,ups,numunspents,remains,mode)) != 0 ) + break; + if ( up != 0 ) + { + spend->input_satoshis += up->value; + spend->inputs[spend->numinputs++] = *up; + if ( spend->input_satoshis >= spend->satoshis ) + { + spend->netamount = (spend->input_satoshis - spend->satoshis); + spend->change = (spend->input_satoshis - spend->netamount) - txfee; + printf("numinputs %d -> (%.8f - spend %.8f) = net %.8f vs amount %.8f change %.8f -> txfee %.8f vs chainfee %.8f\n",spend->numinputs,dstr(spend->input_satoshis),dstr(spend->satoshis),dstr(spend->netamount),dstr(amount),dstr(spend->change),dstr(spend->input_satoshis - spend->change - spend->netamount),dstr(txfee)); + break; + } + remains -= up->value; + } else break; + } + if ( spend->input_satoshis >= spend->satoshis ) + { + spend = realloc(spend,sizeof(*spend) + sizeof(*spend->inputs) * spend->numinputs); + return(spend); + } + else + { + free(spend); + return(0); + } +} + +void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON *txobj,uint32_t sequence) +{ + int32_t i; + for (i=0; inuminputs; i++) + { + spend->inputs[i].sequence = sequence; + bitcoin_addinput(coin,txobj,spend->inputs[i].txid,spend->inputs[i].vout,spend->inputs[i].sequence,spend->inputs[i].spendscript,spend->inputs[i].spendlen); + } +} + +cJSON *iguana_signtx(struct iguana_info *coin,bits256 *txidp,char **signedtxp,struct bitcoin_spend *spend,cJSON *txobj) +{ + int32_t i,j; char *rawtxstr; struct vin_info V; bits256 txid; + for (i=0; inuminputs; i++) // N times less efficient, but for small number of inputs ok + { + if ( *signedtxp != 0 ) + { + free_json(txobj); + txobj = bitcoin_hex2json(coin,&txid,0,*signedtxp); + free(*signedtxp); + } + if ( (rawtxstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 ) + { + memset(&V,0,sizeof(V)); + for (j=0; jinputs[i].privkeys)/sizeof(*spend->inputs[i].privkeys); j++) + { + if ( bits256_nonz(spend->inputs[i].privkeys[j]) > 0 ) + V.signers[j].privkey = spend->inputs[i].privkeys[j]; + } + if ( spend->inputs[i].spendlen > 0 ) + { + memcpy(V.spendscript,spend->inputs[i].spendscript,spend->inputs[i].spendlen); + V.spendlen = spend->inputs[i].spendlen; + } + V.sequence = spend->inputs[i].sequence; + //printf("json2hex.(%s)\n",rawtxstr); + bitcoin_verifytx(coin,txidp,signedtxp,rawtxstr,&V); + //printf("json2hex.(%s)\n",rawtxstr); + free(rawtxstr); + } else break; + } + if ( *signedtxp != 0 && i != spend->numinputs ) + free(*signedtxp), *signedtxp = 0; return(txobj); } +#ifdef testing char *bitcoin_cltvtx(struct iguana_info *coin,char *changeaddr,char *senderaddr,char *senders_otheraddr,char *otheraddr,uint32_t locktime,uint64_t satoshis,bits256 txid,int32_t vout,uint64_t inputsatoshis,bits256 privkey) { uint64_t change; char *rawtxstr,*signedtx; struct vin_info V; bits256 cltxid,signedtxid; @@ -1365,6 +1810,20 @@ char *bitcoin_cltvtx(struct iguana_info *coin,char *changeaddr,char *senderaddr, free_json(txobj); return(signedtx); } +#endif + +char *refstr = "01000000\ +01\ +eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2\ +01000000\ +8c\ +4930460221009e0339f72c793a89e664a8a932df073962a3f84eda0bd9e02084a6a9567f75aa022100bd9cbaca2e5ec195751efdfac164b76250b1e21302e51ca86dd7ebd7020cdc0601410450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6\ +ffffffff\ +01\ +605af40500000000\ +19\ +76a914097072524438d003d23a2f23edb65aae1bb3e46988ac\ +00000000"; cJSON *bitcoin_txtest(struct iguana_info *coin,char *rawtxstr,bits256 txid) { @@ -1445,22 +1904,37 @@ rawtxstr = refstr; return(cJSON_Parse("{\"error\":\"testing bitcoin txbytes\"}")); } -uint64_t bitcoin_parseunspent(struct bitcoin_unspent *unspent,double minconfirms,char *account,cJSON *item) +uint64_t bitcoin_parseunspent(struct iguana_info *coin,struct bitcoin_unspent *unspent,double minconfirms,char *account,cJSON *item) { - uint64_t value = 0; char *hexstr; - // struct bitcoin_unspent { bits256 txid,privkey; uint64_t value; int32_t vout; }; + uint8_t addrtype; char *hexstr,*wifstr,coinaddr[64],args[128]; memset(unspent,0,sizeof(*unspent)); if ( jstr(item,"address") != 0 ) - bitcoin_addr2rmd160(&unspent->addrtype,unspent->rmd160,jstr(item,"address")); - if ( (account == 0 || jstr(item,"account") == 0 || strcmp(account,jstr(item,"account")) == 0) && (minconfirms < 0 || juint(item,"confirmations") >= minconfirms-SMALLVAL) ) { - if ( (hexstr= jstr(item,"scriptPubKey")) != 0 && strlen(hexstr) < sizeof(unspent->script)/2 ) - decode_hex(unspent->script,(int32_t)strlen(hexstr),hexstr); + safecopy(coinaddr,jstr(item,"address"),sizeof(coinaddr)); + bitcoin_addr2rmd160(&unspent->addrtype,unspent->rmd160,coinaddr); + sprintf(args,"[\"%s\"]",coinaddr); + wifstr = bitcoind_RPC(0,coin->symbol,coin->chain->serverport,coin->chain->userpass,"dumpprivkey",args); + if ( wifstr != 0 ) + { + btc_wif2priv(&addrtype,unspent->privkeys[0].bytes,wifstr); + //printf("wifstr.(%s) -> %s\n",wifstr,bits256_str(str,unspent->privkeys[0])); + free(wifstr); + } else fprintf(stderr,"error (%s) cant find privkey\n",coinaddr); + } + if ( (account == 0 || jstr(item,"account") == 0 || strcmp(account,jstr(item,"account")) == 0) && (minconfirms <= 0 || juint(item,"confirmations") >= minconfirms-SMALLVAL) ) + { + if ( (hexstr= jstr(item,"scriptPubKey")) != 0 ) + { + unspent->spendlen = (int32_t)strlen(hexstr) >> 1; + if ( unspent->spendlen < sizeof(unspent->spendscript) ) + decode_hex(unspent->spendscript,unspent->spendlen,hexstr); + } unspent->txid = jbits256(item,"txid"); - unspent->value = j64bits(item,"amount"); + unspent->value = SATOSHIDEN * jdouble(item,"amount"); unspent->vout = jint(item,"vout"); - } - return(value); + //char str[65]; printf("(%s) -> %s %.8f scriptlen.%d\n",jprint(item,0),bits256_str(str,unspent->txid),dstr(unspent->value),unspent->scriptlen); + } else printf("skip.(%s) minconfirms.%f\n",jprint(item,0),minconfirms); + return(unspent->value); } struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,char **retstrp,double *balancep,int32_t *numunspentsp,double minconfirms,char *account) @@ -1474,18 +1948,28 @@ struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct i sprintf(params,"%.0f, 99999999",minconfirms); if ( (retstr= bitcoind_passthru(coin->symbol,coin->chain->serverport,coin->chain->userpass,"listunspent",params)) != 0 ) { - printf("unspents.(%s)\n",retstr); + //printf("sss unspents.(%s)\n",retstr); if ( (utxo= cJSON_Parse(retstr)) != 0 ) { + n = 0; if ( (*numunspentsp= cJSON_GetArraySize(utxo)) > 0 ) { unspents = calloc(*numunspentsp,sizeof(*unspents)); - for (i=n=0; i<*numunspentsp; i++) - if ( (value= bitcoin_parseunspent(&unspents[n],minconfirms,account,jitem(utxo,i))) != 0 ) - total += value, n++; - } else printf("numunspents.%d\n",*numunspentsp); + for (i=0; i<*numunspentsp; i++) + { + value = bitcoin_parseunspent(coin,&unspents[n],minconfirms,account,jitem(utxo,i)); + //printf("i.%d n.%d value %.8f\n",i,n,dstr(value)); + if ( value != 0 ) + { + total += value; + n++; + } + } + } + printf("numunspents.%d -> %d total %.8f\n",*numunspentsp,n,dstr(total)); + *numunspentsp = n; free_json(utxo); - } + } else printf("error parsing.(%s)\n",retstr); if ( retstrp != 0 ) *retstrp = retstr; else free(retstr); @@ -1752,7 +2236,7 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount { struct vin_info V; uint8_t p2sh_rmd160[20],serialized[2096]; char msigaddr[64],*retstr; cJSON *retjson,*txobj; struct iguana_info *active; - bits256 signedtxid; char *signedtx; int scriptlens[1]; + bits256 signedtxid; char *signedtx; struct iguana_msgtx msgtx; if ( (active= iguana_coinfind(activecoin)) == 0 ) return(clonestr("{\"error\":\"activecoin isnt active\"}")); @@ -1764,7 +2248,6 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount bitcoin_txaddspend(active,txobj,destaddress,destamount); if ( destaddress2[0] != 0 && destamount2 > 0. ) bitcoin_txaddspend(active,txobj,destaddress2,destamount2); - bitcoin_addinput(active,txobj,vintxid,vinvout,0xffffffff); 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,wifC)) != 0 ) @@ -1773,10 +2256,10 @@ P2SH_SPENDAPI(iguana,spendmsig,activecoin,vintxid,vinvout,destaddress,destamount return(retstr); V.M = M, V.N = N, V.type = IGUANA_SCRIPT_P2SH; V.p2shlen = bitcoin_MofNspendscript(p2sh_rmd160,V.p2shscript,0,&V); + bitcoin_addinput(active,txobj,vintxid,vinvout,0xffffffff,V.p2shscript,V.p2shlen); bitcoin_address(msigaddr,active->chain->p2shtype,V.p2shscript,V.p2shlen); - scriptlens[0] = 0; retjson = cJSON_CreateObject(); - if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,scriptlens,&msgtx,serialized,sizeof(serialized),&V,0) == 0 ) + if ( bitcoin_verifyvins(active,&signedtxid,&signedtx,&msgtx,serialized,sizeof(serialized),&V,0) == 0 ) { jaddstr(retjson,"result","msigtx"); if ( signedtx != 0 ) diff --git a/iguana/exchanges/bitcoin.h b/iguana/exchanges/bitcoin.h index 38499e005..2032b5d36 100755 --- a/iguana/exchanges/bitcoin.h +++ b/iguana/exchanges/bitcoin.h @@ -34,14 +34,15 @@ #define SCRIPT_OP_RETURN 0x6a #define SCRIPT_OP_DUP 0x76 #define SCRIPT_OP_ENDIF 0x68 -#define OP_DROP 0x75 +#define SCRIPT_OP_DROP 0x75 #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 OP_CHECKSEQUENCEVERIFY 0xb2 -#define OP_CHECKLOCKTIMEVERIFY 0xb1 +#define SCRIPT_OP_CHECKSEQUENCEVERIFY 0xb2 +#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 + struct bp_key { EC_KEY *k; }; diff --git a/iguana/iguana777.h b/iguana/iguana777.h index f8f440a2e..7268f41e2 100755 --- a/iguana/iguana777.h +++ b/iguana/iguana777.h @@ -230,7 +230,7 @@ struct iguana_msgblock uint32_t txn_count; } __attribute__((packed)); -struct iguana_msgvin { bits256 prev_hash; uint8_t *script; uint32_t prev_vout,scriptlen,sequence; } __attribute__((packed)); +struct iguana_msgvin { bits256 prev_hash; uint8_t *sigscript,*spendscript; uint32_t prev_vout,scriptlen,spendlen,sequence; } __attribute__((packed)); struct iguana_msgvout { uint64_t value; uint32_t pk_scriptlen; uint8_t *pk_script; } __attribute__((packed)); @@ -475,7 +475,7 @@ struct vin_signer { bits256 privkey; char coinaddr[64]; uint8_t siglen,sig[80],r struct vin_info { struct iguana_msgvin vin; - int32_t M,N,validmask,spendlen,type,p2shlen; + int32_t M,N,validmask,spendlen,type,p2shlen; uint32_t sequence; struct vin_signer signers[16]; char coinaddr[65]; uint8_t rmd160[20],spendscript[IGUANA_MAXSCRIPTSIZE],p2shscript[IGUANA_MAXSCRIPTSIZE]; @@ -755,13 +755,14 @@ cJSON *iguana_signtx(struct iguana_info *coin,bits256 *txidp,char **signedtxp,st cJSON *bitcoin_createtx(struct iguana_info *coin,int32_t locktime); cJSON *bitcoin_addoutput(struct iguana_info *coin,cJSON *txobj,uint8_t *paymentscript,int32_t len,uint64_t satoshis); int32_t bitcoin_changescript(struct iguana_info *coin,uint8_t *changescript,int32_t n,uint64_t *changep,char *changeaddr,uint64_t inputsatoshis,uint64_t satoshis,uint64_t txfee); -cJSON *bitcoin_addinput(struct iguana_info *coin,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequence); +cJSON *bitcoin_addinput(struct iguana_info *coin,cJSON *txobj,bits256 txid,int32_t vout,uint32_t sequence,uint8_t *script,int32_t scriptlen); int32_t bitcoin_verifytx(struct iguana_info *coin,bits256 *signedtxidp,char **signedtx,char *rawtxstr,struct vin_info *V); char *bitcoin_json2hex(struct iguana_info *coin,bits256 *txidp,cJSON *txjson); int32_t bitcoin_addr2rmd160(uint8_t *addrtypep,uint8_t rmd160[20],char *coinaddr); char *issue_startForging(struct supernet_info *myinfo,char *secret); struct bitcoin_unspent *iguana_unspentsget(struct supernet_info *myinfo,struct iguana_info *coin,char **retstrp,double *balancep,int32_t *numunspentsp,double minconfirms,char *account); void iguana_chainparms(struct iguana_chain *chain,cJSON *argjson); +void iguana_addinputs(struct iguana_info *coin,struct bitcoin_spend *spend,cJSON *txobj,uint32_t sequence); extern queue_t bundlesQ; diff --git a/iguana/iguana_instantdex.c b/iguana/iguana_instantdex.c index afa0e7b1f..314af1952 100755 --- a/iguana/iguana_instantdex.c +++ b/iguana/iguana_instantdex.c @@ -137,8 +137,8 @@ struct instantdex_stateinfo *instantdex_statecreate(struct instantdex_stateinfo state = &states[*numstatesp]; instantdex_stateinit(states,*numstatesp,state,name,errorstr,timeoutstr,process_func,timeout_func); state->initialstate = initialstate; - state->ind = (*numstatesp)++; printf("STATES[%d] %s %p %p %d %d\n",*numstatesp,state->name,state->process,state->timeout,state->timeoutind,state->errorind); + state->ind = (*numstatesp)++; } else { @@ -187,7 +187,8 @@ struct instantdex_event *instantdex_addevent(struct instantdex_stateinfo *states double instantdex_FSMtest(struct instantdex_stateinfo *states,int32_t numstates,int32_t maxiters) { - int32_t i,most,r,n,m=0,initials[100]; struct instantdex_stateinfo *state; struct instantdex_event *event; double sum = 0.; + int32_t i,most,r,r2,n,m=0,initials[100],nextstate=-1; + struct instantdex_stateinfo *state; struct instantdex_event *event; double sum = 0.; if ( maxiters < 1 ) maxiters = 1; for (i=n=most=0; iname[0] == 0 || state->ind >= numstates ) + { + printf("illegal state.(%s) %d? ind.%d >= numstates.%d\n",state->name,nextstate,state->ind,numstates); + break; + } m = 0; - while ( m++ < 1000 && state->initialstate >= 0 && state->numevents ) + while ( m++ < 1000 && state->initialstate >= 0 && state->numevents != 0 ) { if ( (i % 1000000) == 0 ) fprintf(stderr,"%s ",state->name); - event = &state->events[rand() % state->numevents]; - if ( event->nextstateind < 0 ) + r2 = rand() % state->numevents; + event = &state->events[r2]; + if ( (nextstate= event->nextstateind) < 0 ) + break; + if ( event->nextstateind >= numstates ) + { + printf("nextstateind overflow? %d vs %d\n",event->nextstateind,numstates); break; + } state = &states[event->nextstateind]; } if ( m > most ) @@ -911,6 +923,8 @@ char *instantdex_sendoffer(struct supernet_info *myinfo,struct exchange_info *ex return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}")); else if ( (retstr= instantdex_addfeetx(myinfo,newjson,ap,swap,"BOB_sentoffer","ALICE_sentoffer")) == 0 ) { + instantdex_bobtx(myinfo,iguana_coinfind("BTCD"),&swap->deposittxid,swap->otherpubs[0],swap->mypubs[0],swap->privkeys[swap->choosei],ap->offer.expiration-INSTANTDEX_LOCKTIME*2,swap->satoshis[1],1); + instantdex_alicetx(myinfo,iguana_coinfind("BTCD"),swap->altmsigaddr,&swap->altpaymenttxid,swap->pubAm,swap->pubBn,swap->satoshis[0]); if ( 0 ) { int32_t i; diff --git a/iguana/iguana_msg.c b/iguana/iguana_msg.c index 64a45f816..ea8b4898d 100755 --- a/iguana/iguana_msg.c +++ b/iguana/iguana_msg.c @@ -320,8 +320,8 @@ int32_t iguana_rwvin(int32_t rwflag,struct OS_memspace *mem,uint8_t *serialized, len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout); len += iguana_rwvarint32(rwflag,&serialized[len],&msg->scriptlen); if ( rwflag == 0 ) - msg->script = iguana_memalloc(mem,msg->scriptlen,1); - len += iguana_rwmem(rwflag,&serialized[len],msg->scriptlen,msg->script); + msg->sigscript = iguana_memalloc(mem,msg->scriptlen,1); + len += iguana_rwmem(rwflag,&serialized[len],msg->scriptlen,msg->sigscript); len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence); //char str[65]; printf("MSGvin.(%s/v%d) script[%d]\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->scriptlen); //int i; for (i=0; iscriptlen; i++) diff --git a/iguana/iguana_pubkeys.c b/iguana/iguana_pubkeys.c index a5298137d..1e82f8c52 100755 --- a/iguana/iguana_pubkeys.c +++ b/iguana/iguana_pubkeys.c @@ -652,7 +652,7 @@ int32_t btc_priv2wif(char *wifstr,uint8_t privkey[32],uint8_t addrtype) strcpy(wifstr,btc_addr->str); cstr_free(btc_addr,true); } - printf("-> (%s) -> wif.(%s) addrtype.%02x\n",hexstr,wifstr,addrtype); + //printf("-> (%s) -> wif.(%s) addrtype.%02x\n",hexstr,wifstr,addrtype); return(0); } @@ -668,7 +668,7 @@ int32_t btc_wif2priv(uint8_t *addrtypep,uint8_t privkey[32],char *wifstr) len = (int32_t)cstr->len; char tmp[138]; btc_priv2wif(tmp,privkey,*addrtypep); - printf("addrtype.%02x wifstr.(%llx) privlen.%d\n",*addrtypep,*(long long *)privkey,len); + //printf("addrtype.%02x wifstr.(%llx) privlen.%d\n",*addrtypep,*(long long *)privkey,len); cstr_free(cstr,true); } return(len); diff --git a/iguana/iguana_ramchain.c b/iguana/iguana_ramchain.c index bf218c981..f572780d2 100755 --- a/iguana/iguana_ramchain.c +++ b/iguana/iguana_ramchain.c @@ -1482,7 +1482,7 @@ long iguana_ramchain_data(struct iguana_info *coin,struct iguana_peer *addr,stru for (j=0; jtx_in; j++) { //char str[65]; printf("PT vin.%d %s vout.%d\n",j,bits256_str(str,tx->vins[j].prev_hash),tx->vins[j].prev_vout); - iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,tx->vins[j].prev_hash,tx->vins[j].prev_vout,tx->vins[j].script,tx->vins[j].scriptlen,tx->vins[j].sequence);//,bp->hdrsi,bundlei); + iguana_ramchain_addspend256(coin,RAMCHAIN_ARG,tx->vins[j].prev_hash,tx->vins[j].prev_vout,tx->vins[j].sigscript,tx->vins[j].scriptlen,tx->vins[j].sequence);//,bp->hdrsi,bundlei); } } //char str[65]; printf("before height.%d num.%d:%d T.%d U.%d S.%d P.%d X.%d %s\n",ramchain->height,ramchain->numblocks,ramchain->H.data->numblocks,ramchain->H.txidind,ramchain->H.unspentind,ramchain->H.spendind,ramchain->pkind,ramchain->externalind,bits256_str(str,ramchain->H.data->firsthash2)); diff --git a/iguana/iguana_tx.c b/iguana/iguana_tx.c index 689e14c17..c50d9cf6a 100755 --- a/iguana/iguana_tx.c +++ b/iguana/iguana_tx.c @@ -335,108 +335,3 @@ cJSON *iguana_blockjson(struct iguana_info *coin,struct iguana_block *block,int3 jaddnum(retitem,"result",coin->blocks.hwmchain.height); return(jprint(retitem,1)); }*/ - -struct bitcoin_unspent *iguana_bestfit(struct iguana_info *coin,struct bitcoin_unspent *unspents,int32_t numunspents,uint64_t value,int32_t mode) -{ - int32_t i; uint64_t above,below,gap,atx_value; struct bitcoin_unspent *vin,*abovevin,*belowvin; - abovevin = belowvin = 0; - for (above=below=i=0; ivalue; - //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); -} - -struct bitcoin_spend *iguana_spendset(struct supernet_info *myinfo,struct iguana_info *coin,int64_t amount,int64_t txfee,char *account) -{ - int32_t i,mode,numunspents,maxinputs = 1024; int64_t remains; struct bitcoin_unspent *ptr,*up; - struct bitcoin_unspent *ups; struct bitcoin_spend *spend; double balance; - if ( (ups= iguana_unspentsget(myinfo,coin,0,&balance,&numunspents,coin->chain->minconfirms,account)) == 0 ) - return(0); - spend = calloc(1,sizeof(*spend) + sizeof(*spend->inputs) * maxinputs); - spend->txfee = txfee; - remains = txfee + amount; - spend->satoshis = remains; - ptr = spend->inputs; - for (i=0; i=0; mode--) - if ( (up= iguana_bestfit(coin,ups,numunspents,remains,mode)) != 0 ) - break; - if ( up != 0 ) - { - spend->input_satoshis += up->value; - spend->inputs[spend->numinputs++] = *up; - if ( spend->input_satoshis >= spend->satoshis ) - { - spend->netamount = (spend->input_satoshis - spend->satoshis); - spend->change = (spend->input_satoshis - spend->netamount); - printf("numinputs %d sum %.8f vs amount %.8f change %.8f -> txfee %.8f\n",spend->numinputs,dstr(spend->input_satoshis),dstr(amount),dstr(spend->change),dstr(spend->input_satoshis - spend->change - spend->netamount)); - break; - } - remains -= up->value; - } else break; - } - if ( spend->input_satoshis >= spend->satoshis ) - { - spend = realloc(spend,sizeof(*spend) + sizeof(*spend->inputs) * spend->numinputs); - return(spend); - } - else - { - free(spend); - return(0); - } -} - -cJSON *iguana_signtx(struct iguana_info *coin,bits256 *txidp,char **signedtxp,struct bitcoin_spend *spend,cJSON *txobj) -{ - int32_t i,j; char *rawtxstr; struct vin_info V; bits256 txid; - for (i=0; inuminputs; i++) - bitcoin_addinput(coin,txobj,spend->inputs[i].txid,spend->inputs[i].vout,0xffffffff); - for (i=0; inuminputs; i++) // N times less efficient, but for small number of inputs ok - { - if ( *signedtxp != 0 ) - { - free_json(txobj); - txobj = bitcoin_hex2json(coin,&txid,0,*signedtxp); - free(*signedtxp); - } - if ( (rawtxstr= bitcoin_json2hex(coin,&txid,txobj)) != 0 ) - { - memset(&V,0,sizeof(V)); - for (j=0; jinputs[i].privkeys)/sizeof(*spend->inputs[i].privkeys); j++) - if ( bits256_nonz(spend->inputs[i].privkeys[j]) > 0 ) - V.signers[j].privkey = spend->inputs[i].privkeys[j]; - bitcoin_verifytx(coin,txidp,signedtxp,rawtxstr,&V); - free(rawtxstr); - } else break; - } - if ( *signedtxp != 0 && i != spend->numinputs ) - free(*signedtxp), *signedtxp = 0; - return(txobj); -} diff --git a/iguana/swaps/iguana_BTCswap.c b/iguana/swaps/iguana_BTCswap.c index ca0e34038..541bedbc0 100755 --- a/iguana/swaps/iguana_BTCswap.c +++ b/iguana/swaps/iguana_BTCswap.c @@ -91,25 +91,36 @@ int32_t instantdex_outputinsurance(struct iguana_info *coin,cJSON *txobj,int64_t decode_hex(rmd160,sizeof(rmd160),(orderid % 10) == 0 ? TIERNOLAN_RMD160 : INSTANTDEX_RMD160); script[n++] = sizeof(uint64_t); n += iguana_rwnum(1,&script[n],sizeof(orderid),&orderid); - script[n++] = OP_DROP; + script[n++] = SCRIPT_OP_DROP; n = bitcoin_standardspend(script,n,rmd160); bitcoin_addoutput(coin,txobj,script,n,insurance); return(n); } +void disp_tx(struct supernet_info *myinfo,struct iguana_info *coin,char *str,char *txbytes) +{ + cJSON *txobj; bits256 txid; + txobj = bitcoin_hex2json(coin,&txid,0,txbytes); + printf("%s.(%s)\n",str,jprint(txobj,1)); +} + char *instantdex_feetx(struct supernet_info *myinfo,bits256 *txidp,struct instantdex_accept *A) { - int32_t n; char *feetx = 0; struct iguana_info *coinbtc; cJSON *txobj; struct bitcoin_spend *spend; int64_t insurance; - if ( (coinbtc= iguana_coinfind("BTC")) != 0 ) + int32_t n; char *feetx = 0; struct iguana_info *coin; cJSON *txobj; struct bitcoin_spend *spend; int64_t insurance; + if ( (coin= iguana_coinfind("BTCD")) != 0 ) { - insurance = instantdex_insurance(coinbtc,instantdex_BTCsatoshis(A->offer.price64,A->offer.basevolume64)); - if ( (spend= iguana_spendset(myinfo,coinbtc,insurance,coinbtc->chain->txfee,0)) != 0 ) + insurance = 40 * instantdex_insurance(coin,instantdex_BTCsatoshis(A->offer.price64,A->offer.basevolume64)); + if ( (spend= iguana_spendset(myinfo,coin,insurance,coin->chain->txfee,0)) != 0 ) { - txobj = bitcoin_createtx(coinbtc,0); - n = instantdex_outputinsurance(coinbtc,txobj,insurance,A->orderid); - txobj = iguana_signtx(coinbtc,txidp,&feetx,spend,txobj); + txobj = bitcoin_createtx(coin,0); + n = instantdex_outputinsurance(coin,txobj,insurance,A->orderid); + iguana_addinputs(coin,spend,txobj,0xffffffff); + txobj = iguana_signtx(coin,txidp,&feetx,spend,txobj); if ( feetx != 0 ) + { printf("%s feetx.%s\n",A->offer.myside != 0 ? "BOB" : "ALICE",feetx); + disp_tx(myinfo,coin,"feetx",feetx); + } else printf("error signing %s feetx numinputs.%d\n",A->offer.myside != 0 ? "BOB" : "ALICE",spend->numinputs); free(spend); } @@ -167,10 +178,13 @@ char *instantdex_bobtx(struct supernet_info *myinfo,struct iguana_info *coin,bit calc_rmd160_sha256(secret,priv.bytes,sizeof(priv)); n = instantdex_bobscript(script,0,&secretstart,locktime,pub1,secret,pub2); bitcoin_addoutput(coin,txobj,script,n,amount + depositflag*insurance*100); + iguana_addinputs(coin,spend,txobj,0xffffffff); txobj = iguana_signtx(coin,txidp,&signedtx,spend,txobj); if ( signedtx != 0 ) + { printf("bob deposit.%s\n",signedtx); - else printf("error signing bobdeposit numinputs.%d\n",spend->numinputs); + disp_tx(myinfo,coin,depositflag != 0 ? "deposit" : "payment",signedtx); + } else printf("error signing bobdeposit numinputs.%d\n",spend->numinputs); free(spend); } free_json(txobj); @@ -260,9 +274,13 @@ char *instantdex_alicetx(struct supernet_info *myinfo,struct iguana_info *altcoi txobj = bitcoin_createtx(altcoin,0); n = instantdex_alicescript(script,0,msigaddr,altcoin->chain->p2shtype,pubAm,pubBn); bitcoin_addoutput(altcoin,txobj,script,n,amount); + iguana_addinputs(altcoin,spend,txobj,0xffffffff); txobj = iguana_signtx(altcoin,txidp,&signedtx,spend,txobj); if ( signedtx != 0 ) + { printf("alice payment.%s\n",signedtx); + disp_tx(myinfo,altcoin,"altpayment",signedtx); + } else printf("error signing alicetx numinputs.%d\n",spend->numinputs); free(spend); free_json(txobj); @@ -683,7 +701,6 @@ cJSON *BTC_cleanupfunc(struct supernet_info *myinfo,struct exchange_info *exchan struct instantdex_stateinfo *BTC_initFSM(int32_t *n) { struct instantdex_stateinfo *s = 0; - *n = 2; // Four initial states are BOB_sentoffer, ALICE_gotoffer, ALICE_sentoffer, BOB_gotoffer // the initiator includes signed feetx and deck of INSTANTDEX_DECKSIZE keypairs // @@ -694,8 +711,9 @@ struct instantdex_stateinfo *BTC_initFSM(int32_t *n) // states instantdex_statecreate(s,n,,handlerfunc,errorhandler,, // a given state has a couple of handlers and custom events, with timeouts and errors invoking a bypass + *n = 2; s = instantdex_statecreate(s,n,"BTC_cleanup",BTC_cleanupfunc,0,0,0,-1); // from states without any commits - + memset(s,0,sizeof(*s) * 2); s = instantdex_statecreate(s,n,"BOB_reclaim",BOB_reclaimfunc,0,0,0,0); // Bob's gets his deposit back instantdex_addevent(s,*n,"BOB_reclaim","brcfound","poll","BTC_cleanup"); instantdex_addevent(s,*n,"BOB_reclaim","poll","poll","BOB_reclaim");