diff --git a/.gitignore b/.gitignore index 33bdcdf67..a2bbf84d8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ bitcoin-send-tx bitcoin-spv bitcoin-txref nspv +.vscode Makefile configure diff --git a/coins b/coins index 23ede6fb5..1f89ffeb0 100644 --- a/coins +++ b/coins @@ -106,6 +106,16 @@ "magic":"f60d75fd", "nSPV": "27.102.107.29, 27.102.107.28, 27.102.107.27" }, + { + "coin": "BTCH", + "asset": "BTCH", + "fname": "Bitcoin Hush", + "rpcport": 8800, + "mm2": 1, + "p2p": 8799, + "magic":"f41c5eff", + "nSPV":"136.243.58.134" + }, { "coin": "NSPV", "asset": "NSPV", @@ -2100,12 +2110,6 @@ "wiftype": 151, "txfee": 100000 }, - { - "coin": "BTCH", - "asset": "BTCH", - "fname": "Bitcoin Hush", - "rpcport": 8800 - }, { "coin": "ETOMIC", "asset": "ETOMIC", diff --git a/include/btc/script.h b/include/btc/script.h index 3e9fe3a0c..f5cde0d13 100644 --- a/include/btc/script.h +++ b/include/btc/script.h @@ -170,6 +170,8 @@ enum opcodetype { OP_CHECKSIGVERIFY = 0xad, OP_CHECKMULTISIG = 0xae, OP_CHECKMULTISIGVERIFY = 0xaf, + OP_CHECKCRYPTOCONDITION = 0xcc, + OP_CHECKCRYPTOCONDITIONVERIFY = 0xcd, // expansion OP_NOP1 = 0xb0, diff --git a/include/nSPV_defs.h b/include/nSPV_defs.h index f2604b561..c4e342df7 100644 --- a/include/nSPV_defs.h +++ b/include/nSPV_defs.h @@ -90,11 +90,16 @@ struct rpcrequest_info #define NSPV_TXIDSRESP 0x0f #define NSPV_MEMPOOL 0x10 #define NSPV_MEMPOOLRESP 0x11 +#define NSPV_CCMODULEUTXOS 0x12 +#define NSPV_CCMODULEUTXOSRESP 0x13 #define NSPV_MEMPOOL_ALL 0 #define NSPV_MEMPOOL_ADDRESS 1 #define NSPV_MEMPOOL_ISSPENT 2 #define NSPV_MEMPOOL_INMEMPOOL 3 #define NSPV_MEMPOOL_CCEVALCODE 4 +#define NSPV_CC_TXIDS 16 +#define NSPV_REMOTERPC 0x14 +#define NSPV_REMOTERPCRESP 0x15 #define COIN SATOSHIDEN @@ -221,6 +226,12 @@ struct NSPV_CCmtxinfo struct NSPV_utxoresp used[NSPV_MAXVINS]; }; +struct NSPV_remoterpcresp +{ + char method[64]; + char json[11000]; +}; + struct NSPV_header { int32_t height; diff --git a/src/tools/cryptoconditions/src/cryptoconditions.c b/src/tools/cryptoconditions/src/cryptoconditions.c index 12f973b97..b366c1ea3 100644 --- a/src/tools/cryptoconditions/src/cryptoconditions.c +++ b/src/tools/cryptoconditions/src/cryptoconditions.c @@ -143,14 +143,32 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t length) { void asnCondition(const CC *cond, Condition_t *asn) { asn->present = cc_isAnon(cond) ? cond->conditionType->asnType : cond->type->asnType; - // This may look a little weird - we dont have a reference here to the correct - // union choice for the condition type, so we just assign everything to the threshold - // type. This works out nicely since the union choices have the same binary interface. - CompoundSha256Condition_t *choice = &asn->choice.thresholdSha256; - choice->cost = cc_getCost(cond); - choice->fingerprint.buf = cond->type->fingerprint(cond); - choice->fingerprint.size = 32; - choice->subtypes = asnSubtypes(cond->type->getSubtypes(cond)); + // Fixed previous implementation as it was treating every asn as thresholdSha256 type and it was memory leaking + // because SimpleSha256Condition_t types do not have subtypes so it couldn't free it in the end. + int typeId=cond->type->typeId; + if (asn->present==Condition_PR_thresholdSha256 || asn->present==Condition_PR_prefixSha256) + { + CompoundSha256Condition_t *sequence=asn->present==Condition_PR_thresholdSha256?&asn->choice.thresholdSha256:&asn->choice.prefixSha256; + sequence->cost = cc_getCost(cond); + sequence->fingerprint.buf = cond->type->fingerprint(cond); + sequence->fingerprint.size = 32; + sequence->subtypes = asnSubtypes(cond->type->getSubtypes(cond)); + } + else + { + SimpleSha256Condition_t *choice; + switch (asn->present) + { + case Condition_PR_preimageSha256: choice = &asn->choice.preimageSha256; break; + case Condition_PR_rsaSha256: choice = &asn->choice.rsaSha256; break; + case Condition_PR_ed25519Sha256: choice = &asn->choice.ed25519Sha256; break; + case Condition_PR_secp256k1Sha256: choice = &asn->choice.secp256k1Sha256; break; + case Condition_PR_evalSha256: choice = &asn->choice.evalSha256; break; + }; + choice->cost = cc_getCost(cond); + choice->fingerprint.buf = cond->type->fingerprint(cond); + choice->fingerprint.size = 32; + } } diff --git a/src/tools/cryptoconditions/src/secp256k1.c b/src/tools/cryptoconditions/src/secp256k1.c index a16115bb8..01828a98b 100644 --- a/src/tools/cryptoconditions/src/secp256k1.c +++ b/src/tools/cryptoconditions/src/secp256k1.c @@ -196,6 +196,7 @@ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const u unsigned char publicKey[SECP256K1_PK_SIZE]; size_t ol = SECP256K1_PK_SIZE; secp256k1_ec_pubkey_serialize(ec_ctx_verify, publicKey, &ol, &spk, SECP256K1_EC_COMPRESSED); + if ( 0 ) { int32_t z; for (z=0; z<33; z++) diff --git a/src/tools/cryptoconditions/src/threshold.c b/src/tools/cryptoconditions/src/threshold.c index 9547f4f8c..11107db40 100644 --- a/src/tools/cryptoconditions/src/threshold.c +++ b/src/tools/cryptoconditions/src/threshold.c @@ -213,7 +213,11 @@ static CC *thresholdFromJSON(const cJSON *params, char *err) { for (int i=0; isize; i++) { sub = cJSON_GetArrayItem(subfulfillments_item, i); cond->subconditions[i] = cc_conditionFromJSON(sub, err); - if (err[0]) return NULL; + if (err[0] || cond->subconditions[i]==NULL) + { + if (cond) cc_free(cond); + return NULL; + } } return cond; diff --git a/src/tools/cryptoconditions/src/utils.c b/src/tools/cryptoconditions/src/utils.c index 6a2167119..a21d6edd6 100644 --- a/src/tools/cryptoconditions/src/utils.c +++ b/src/tools/cryptoconditions/src/utils.c @@ -130,7 +130,7 @@ unsigned char *base64_decode(const unsigned char *data_, if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; } - + free(data); return decoded_data; } diff --git a/src/tools/nSPV_CCUtils.h b/src/tools/nSPV_CCUtils.h new file mode 100644 index 000000000..0a1090a46 --- /dev/null +++ b/src/tools/nSPV_CCUtils.h @@ -0,0 +1,201 @@ +#ifndef NSPV_CCUTILS_H +#define NSPV_CCUTILS_H + +#include "tools/cryptoconditions/include/cryptoconditions.h" +#include "../include/btc/script.h" + +#define CC_MAXVINS 1024 + +#define EVAL_FAUCET (0xe4) +const char *FaucetCCaddr = "R9zHrofhRbub7ER77B7NrVch3A63R39GuC"; +const char *FaucetNormaladdr = "RKQV4oYs4rvxAWx1J43VnT73rSTVtUeckk"; +char FaucetCChexstr[67] = { "03682b255c40d0cde8faee381a1a50bbb89980ff24539cb8518e294d3a63cefe12" }; +uint8_t FaucetCCpriv[32] = { 0xd4, 0x4f, 0xf2, 0x31, 0x71, 0x7d, 0x28, 0x02, 0x4b, 0xc7, 0xdd, 0x71, 0xa0, 0x39, 0xc4, 0xbe, 0x1a, 0xfe, 0xeb, 0xc2, 0x46, 0xda, 0x76, 0xf8, 0x07, 0x53, 0x3d, 0x96, 0xb4, 0xca, 0xa0, 0xe9 }; + +typedef struct _CCSigData { + struct CC *cond; // pointer to cryptocondition + uint64_t voutValue; + cstring * voutScriptPubkey; + int32_t vini; + bool isCC; +} CCSigData; + + +void endiancpy(uint8_t *dest,uint8_t *src,int32_t len) +{ + int32_t i,j=0; +#if defined(WORDS_BIGENDIAN) + for (i=31; i>=0; i--) + dest[j++] = src[i]; +#else + memcpy(dest,src,len); +#endif +} + +CC* CCNewEval(char *code,int32_t size) +{ + CC *cond = cc_new(CC_Eval); + cond->code = (uint8_t*) malloc(size); + memcpy(cond->code, code, size); + cond->codeLength = size; + return cond; +} + +CC* CCNewThreshold(int t, CC** v, int size) +{ + CC *cond = cc_new(CC_Threshold); + cond->threshold = t; + cond->size = size; + cond->subconditions = (CC**) calloc(size, sizeof(CC*)); + memcpy(cond->subconditions, v, size * sizeof(CC*)); + return cond; +} + +static unsigned char* CopyPubKey(uint8_t *pkIn) +{ + unsigned char* pk = (unsigned char*) malloc(33); + memcpy(pk, pkIn, 33); + return pk; +} + +CC* CCNewSecp256k1(uint8_t* k) +{ + CC *cond = cc_new(CC_Secp256k1); + cond->publicKey = CopyPubKey(k); + return cond; +} + +CC *MakeCCcond1(uint8_t evalcode,uint8_t *pk) +{ + cstring *ss; + CC *c[1]={CCNewSecp256k1(pk)}; + CC **pks=c; + ss=cstr_new_sz(1); + ser_varlen(ss,evalcode); + CC *condCC = CCNewEval(ss->str,ss->len); + CC *Sig = CCNewThreshold(1, pks, 1); + CC *v[2]= {condCC, Sig}; + CC* cond=CCNewThreshold(2, v ,2); + cstr_free(ss, true); + cc_free(condCC); + cc_free(Sig); + cc_free(*pks); + return cond; +} + +CC *MakeCCcond1of2(uint8_t evalcode,uint8_t *pk1, uint8_t *pk2) +{ + cstring *ss; + + CC *c[2]={CCNewSecp256k1(pk1),CCNewSecp256k1(pk2)}; + + CC **pks=c; + ss=cstr_new_sz(1); + ser_varlen(ss,evalcode); + CC *condCC = CCNewEval(ss->str,ss->len); + CC *Sig = CCNewThreshold(1, pks, 2); + CC *v[2]= {condCC, Sig}; + CC* cond=CCNewThreshold(2, v ,2); + cstr_free(ss, true); + cc_free(condCC); + cc_free(Sig); + cc_free(*pks); + return cond; +} + +void SerializeScript(cstring *script,unsigned char* buf, size_t len) +{ + if (len < OP_PUSHDATA1) ser_varlen(script,len); + else if (len <= 0xFF) + { + ser_varlen(script,OP_PUSHDATA1); + ser_bytes(script,&len,1); + } + else if (len <= 0xFFFF) + { + ser_varlen(script,OP_PUSHDATA2); + ser_u16(script,len); + } + else + { + ser_varlen(script,OP_PUSHDATA4); + ser_u32(script,len); + } + ser_bytes(script,buf,len); + return; +} +cstring* CCPubKey(const CC *cond) +{ + unsigned char buf[1000],ss[1024]; int32_t n=0; + + size_t len = cc_conditionBinary(cond, buf); + cstring* ccpk = cstr_new_sz(len+24); + SerializeScript(ccpk,buf,len); + unsigned char c=OP_CHECKCRYPTOCONDITION; + ser_bytes(ccpk,&c,1); + return ccpk; +} + +void CCSig(const CC *cond,cstring *script) +{ + unsigned char buf[10001]; + size_t len = cc_fulfillmentBinary(cond, buf, 10000); + buf[len++]=SIGHASH_ALL; + SerializeScript(script,buf,len); + return; +} + +btc_tx_out *MakeCC1vout(uint8_t evalcode, uint64_t nValue,uint8_t *pk) +{ + CC *payoutCond = MakeCCcond1(evalcode,pk); + btc_tx_out *vout = btc_tx_out_new(); + vout->script_pubkey = CCPubKey(payoutCond); + vout->value = nValue; + cc_free(payoutCond); + return(vout); +} + +btc_tx_out *MakeCC1of2vout(uint8_t evalcode,uint64_t nValue,uint8_t *pk1,uint8_t *pk2) +{ + btc_tx_out *vout = btc_tx_out_new(); + CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2); + vout->script_pubkey = CCPubKey(payoutCond); + vout->value = nValue; + cc_free(payoutCond); + return(vout); +} + +btc_pubkey *buf2pk(btc_pubkey *pk,uint8_t *buf33) +{ + int32_t i; uint8_t *dest; + pk->compressed=true; + for (i=0; i<33; i++) + pk->pubkey[i] = buf33[i]; + return(pk); +} + +btc_pubkey *CCtxidaddr(btc_spv_client *client,btc_pubkey *pk,char *txidaddr,uint256 txid) +{ + uint8_t buf33[33]; + buf33[0] = 0x02; + btc_pubkey_init(pk); + endiancpy(&buf33[1],(uint8_t *)&txid,32); + buf2pk(pk,buf33); + btc_pubkey_getaddr_p2pkh(pk,client->chainparams,txidaddr); + return(pk); +} + +bool IsPayToCryptoCondition(cstring *script) +{ + vector *v=vector_new(sizeof(btc_script_op),btc_script_op_free_cb); + btc_script_get_ops(script,v); + for(int i=0;i<(int32_t)v->len;i++) + { + btc_script_op *op=vector_idx(v,i); + if (op->op==OP_CHECKCRYPTOCONDITION) return true; + } + return false; +} + +#endif // NSPV_CCUTILS_H + diff --git a/src/tools/nSPV_CCtx.h b/src/tools/nSPV_CCtx.h index 8300c4924..9088b6cc8 100644 --- a/src/tools/nSPV_CCtx.h +++ b/src/tools/nSPV_CCtx.h @@ -17,18 +17,74 @@ #ifndef NSPV_CCTX_H #define NSPV_CCTX_H +#include "nSPV_CCUtils.h" // @blackjok3r and @mihailo implement the CC tx creation functions here // instead of a swissarmy knife finalizeCCtx, i think it is better to pass in the specific info needed into a CC signing function. this would eliminate the comparing to all the different possibilities // since the CC rpc that creates the tx will know which vins are normal and which ones are CC, and most importantly what type of CC vin it is, it will be much simpler finalize function, though it will mean all the CC rpc calls will have to do more work. that was the rationale behind FinalizeCCtx, but i hear a lot of complaints about the complexity it has become. // please make a new way of doing CC tx that wont lead to complaints later. let us start with faucetget -cJSON *NSPV_CC_faucetget() +extern bool NSPV_SignTx(btc_tx *mtx,int32_t vini,int64_t utxovalue,cstring *scriptPubKey,uint32_t nTime); + +cstring *FinalizeCCtx(btc_spv_client *client, cJSON *txdata ) { - cJSON *result = cJSON_CreateObject(); - jaddstr(result,"result","error"); - jaddstr(result,"error","not implemented yet"); - jaddstr(result,"hex","deadbeef"); - jaddstr(result,"lastpeer",NSPV_lastpeer); - return(result); + int32_t i,n,vini; cstring *finalHex,*hex; cJSON *sigData=NULL; char error[256]; int64_t voutValue; + + if (!cJSON_HasObjectItem(txdata,"hex")) return(cstr_new("No field \"hex\" in JSON response from fullnode")); + hex=cstr_new(jstr(txdata,"hex")); + cstr_append_c(hex,0); + btc_tx *mtx=btc_tx_decodehex(hex->str); + cstr_free(hex,1); + if (!mtx) return(cstr_new("Invalid hex in JSON response from fullnode")); + sigData=jarray(&n,txdata,"SigData"); + if (!sigData) return(cstr_new("No field \"SigData\" in JSON response from fullnode")); + for (i=0; istr,script->len); + sigHash=bits256_rev(sigHash); + if ((cc_signTreeSecp256k1Msg32(cond,NSPV_key.privkey,sigHash.bytes))!=0) + { + if (vin->script_sig) + { + cstr_free(vin->script_sig,1); + vin->script_sig=cstr_new(""); + } + CCSig(cond,vin->script_sig); + } + cstr_free(script,1); + cc_free(cond); + } + else + { + cstring *voutScriptPubkey=cstr_new((char *)utils_hex_to_uint8(jstr(item,"scriptPubKey"))); + if (NSPV_SignTx(mtx,vini,voutValue,voutScriptPubkey,0)==0) + { + fprintf(stderr,"signing error for vini.%d\n",vini); + cstr_free(voutScriptPubkey,1); + btc_tx_free(mtx); + return(cstr_new("")); + } + cstr_free(voutScriptPubkey,1); + } + } + finalHex=btc_tx_to_cstr(mtx); + btc_tx_free(mtx); + return (finalHex); } #endif // NSPV_CCTX_H diff --git a/src/tools/nSPV_rpc.h b/src/tools/nSPV_rpc.h index a731db03e..fac2bf9eb 100644 --- a/src/tools/nSPV_rpc.h +++ b/src/tools/nSPV_rpc.h @@ -605,6 +605,7 @@ char *NSPV_rpcparse(int32_t *contentlenp,char *retbuf,int32_t bufsize,int32_t *j //printf("URLMETHOD.(%s)\n",urlmethod); *postflagp = (strcmp(urlmethod,"POST") == 0); //printf("POST.%d rpcparse.(%s)\n",*postflagp,urlstr); + memset(url,0,8192); for (i=0; i<(int32_t)sizeof(url)-1&&urlstr[n+i]!=0&&urlstr[n+i]!=' '; i++) url[i] = urlstr[n+i]; url[i++] = 0; @@ -1160,7 +1161,6 @@ int32_t iguana_socket(int32_t bindflag,char *hostname,uint16_t port) int32_t opt,sock,result; char ipaddr[64],checkipaddr[64]; struct timeval timeout; struct sockaddr_in saddr; socklen_t addrlen,slen; addrlen = sizeof(saddr); - struct hostent *hostent; /** * gethostbyname() is deprecated and cause crash on x64 windows @@ -1168,8 +1168,6 @@ int32_t iguana_socket(int32_t bindflag,char *hostname,uint16_t port) * it is standard posix function and is correctly supported in win32/win64/linux * @author - fadedreamz@gmail.com */ - -#if defined(_M_X64) struct addrinfo *addrresult = NULL; struct addrinfo *returnptr = NULL; struct addrinfo hints; @@ -1180,12 +1178,10 @@ int32_t iguana_socket(int32_t bindflag,char *hostname,uint16_t port) hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; -#endif if ( parse_ipaddr(ipaddr,hostname) != 0 ) port = parse_ipaddr(ipaddr,hostname); -#if defined(_M_X64) retVal = getaddrinfo(ipaddr, NULL, &hints, &addrresult); for (returnptr = addrresult; returnptr != NULL && found == 0; returnptr = returnptr->ai_next) { switch (returnptr->ai_family) { @@ -1204,28 +1200,16 @@ int32_t iguana_socket(int32_t bindflag,char *hostname,uint16_t port) freeaddrinfo(addrresult); return(-1); } -#else - hostent = gethostbyname(ipaddr); - if ( hostent == NULL ) - { - printf("gethostbyname(%s) returned error: %d port.%d ipaddr.(%s)\n",hostname,errno,port,ipaddr); - return(-1); - } -#endif saddr.sin_family = AF_INET; saddr.sin_port = htons(port); //#ifdef _WIN32 // saddr.sin_addr.s_addr = (uint32_t)calc_ipbits("127.0.0.1"); //#else -#if defined(_M_X64) saddr.sin_addr.s_addr = sockaddr_ipv4->sin_addr.s_addr; // graceful cleanup sockaddr_ipv4 = NULL; - freeaddrinfo(addrresult); -#else - memcpy(&saddr.sin_addr.s_addr,hostent->h_addr_list[0],hostent->h_length); -#endif + freeaddrinfo(addrresult); expand_ipbits(checkipaddr,saddr.sin_addr.s_addr); if ( strcmp(ipaddr,checkipaddr) != 0 ) printf("bindflag.%d iguana_socket mismatch (%s) -> (%s)?\n",bindflag,checkipaddr,ipaddr); diff --git a/src/tools/nSPV_structs.h b/src/tools/nSPV_structs.h index 160dfac98..484d001a2 100644 --- a/src/tools/nSPV_structs.h +++ b/src/tools/nSPV_structs.h @@ -500,6 +500,20 @@ void NSPV_broadcast_purge(struct NSPV_broadcastresp *ptr) memset(ptr,0,sizeof(*ptr)); } +int32_t NSPV_rwremoterpcresp(int32_t rwflag,uint8_t *serialized,struct NSPV_remoterpcresp *ptr, int32_t slen) +{ + int32_t len = 0; + len+=iguana_rwbuf(rwflag,&serialized[len],sizeof(ptr->method),(uint8_t *)ptr->method); + len+=iguana_rwbuf(rwflag,&serialized[len],slen-len,(uint8_t *)ptr->json); + return(len); +} + +void NSPV_remoterpc_purge(struct NSPV_remoterpcresp *ptr) +{ + if ( ptr != 0 ) + memset(ptr,0,sizeof(*ptr)); +} + cJSON *NSPV_txproof_json(struct NSPV_txproof *ptr) { char *hexstr; cJSON *result = cJSON_CreateObject(); diff --git a/src/tools/nSPV_superlite.h b/src/tools/nSPV_superlite.h index 9824c9bc5..f2718569f 100644 --- a/src/tools/nSPV_superlite.h +++ b/src/tools/nSPV_superlite.h @@ -56,6 +56,7 @@ struct NSPV_ntzsresp NSPV_ntzsresult; struct NSPV_ntzsproofresp NSPV_ntzsproofresult; struct NSPV_txproof NSPV_txproofresult; struct NSPV_broadcastresp NSPV_broadcastresult; +struct NSPV_remoterpcresp NSPV_remoterpcresult; struct NSPV_ntzsresp NSPV_ntzsresp_cache[NSPV_MAXVINS]; struct NSPV_ntzsproofresp NSPV_ntzsproofresp_cache[NSPV_MAXVINS * 2]; @@ -459,6 +460,11 @@ void komodo_nSPVresp(btc_node *from,uint8_t *response,int32_t len) NSPV_rwbroadcastresp(0,&response[1],&NSPV_broadcastresult); fprintf(stderr,"got broadcast response %u size.%d %s retcode.%d\n",timestamp,len,bits256_str(str,NSPV_broadcastresult.txid),NSPV_broadcastresult.retcode); break; + case NSPV_REMOTERPCRESP: + NSPV_remoterpc_purge(&NSPV_remoterpcresult); + NSPV_rwremoterpcresp(0,&response[1],&NSPV_remoterpcresult,len-1); + fprintf(stderr,"got remoterpc response %u size.%d %s\n",timestamp,len,NSPV_remoterpcresult.method); + break; default: fprintf(stderr,"unexpected response %02x size.%d at %u\n",response[0],len,timestamp); break; } @@ -512,7 +518,7 @@ cJSON *NSPV_getpeerinfo(btc_spv_client *client) return(result); } -cJSON *NSPV_gettransaction2(btc_spv_client *client,bits256 txid,int32_t v,int32_t height) +btc_tx *NSPV_gettx(btc_spv_client *client,bits256 txid,int32_t v,int32_t height) { int32_t retval = 0, isKMD, skipvalidation = 0; int64_t extradata = 0; int64_t rewardsum = 0; btc_tx* tx = NULL; cJSON *result = cJSON_CreateObject(); @@ -520,6 +526,14 @@ cJSON *NSPV_gettransaction2(btc_spv_client *client,bits256 txid,int32_t v,int32_ if ( height == 0 ) height = NSPV_lastntz.height; tx = NSPV_gettransaction(client,&retval,isKMD,skipvalidation,v,txid,height,extradata,NSPV_tiptime,&rewardsum); + return(tx); +} + +cJSON *NSPV_gettransaction2(btc_spv_client *client,bits256 txid,int32_t v,int32_t height) +{ + int32_t retval = 0; int64_t rewardsum = 0; cJSON *result = cJSON_CreateObject(); btc_tx *tx; + + tx = NSPV_gettx(client,txid,v,height); if ( tx == NULL ) { jaddstr(result,"result","error"); @@ -886,6 +900,41 @@ cJSON *NSPV_broadcast(btc_spv_client *client,char *hex) return(NSPV_broadcast_json(&B,txid)); } +cJSON *NSPV_remoterpccall(btc_spv_client *client, char* method, cJSON *request) +{ + uint8_t *msg; int32_t i,iter,len = 3,slen; + char *pubkey=utils_uint8_to_hex(NSPV_pubkey.pubkey,33); + + jaddstr(request,"mypk",pubkey); + NSPV_remoterpc_purge(&NSPV_remoterpcresult); + char *json=cJSON_Print(request); + if (!json) return (NULL); + slen = (int32_t)strlen(json); + msg = (uint8_t *)malloc(4 + sizeof(slen) + slen); + msg[0] = msg[1] = msg[2] = 0; + msg[len++] = NSPV_REMOTERPC; + len += iguana_rwnum(1,&msg[len],sizeof(slen),&slen); + memcpy(&msg[len],json,slen), len += slen; + free(json); + for (iter=0; iter<3; iter++) + if ( NSPV_req(client,0,msg,len,NODE_NSPV,NSPV_REMOTERPC>>1) != 0 ) + { + for (i=0; istr); + cstr_free(hex,1); + cJSON_Delete(req); + return(result); + } + else return (req); + } + else + return(cJSON_Parse("{\"error\":\"invalid method\"}")); } #endif // KOMODO_NSPVSUPERLITE_H diff --git a/src/tools/nSPV_wallet.h b/src/tools/nSPV_wallet.h index 807a5c624..14946b654 100644 --- a/src/tools/nSPV_wallet.h +++ b/src/tools/nSPV_wallet.h @@ -352,7 +352,7 @@ int32_t NSPV_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t int64_t NSPV_addinputs(struct NSPV_utxoresp *used,btc_tx *mtx,int64_t total,int32_t maxinputs,struct NSPV_utxoresp *ptr,int32_t num) { - int32_t abovei,belowi,ind,vout,i,n = 0; int64_t threshold,above,below; int64_t remains,totalinputs = 0; struct NSPV_utxoresp utxos[NSPV_MAXVINS+16],*up; + int32_t abovei,belowi,ind,vout,i,n = 0; int64_t threshold,above,below; int64_t remains,totalinputs = 0; struct NSPV_utxoresp utxos[NSPV_MAXVINS],*up; memset(utxos,0,sizeof(utxos)); if ( maxinputs > NSPV_MAXVINS ) maxinputs = NSPV_MAXVINS; @@ -361,11 +361,13 @@ int64_t NSPV_addinputs(struct NSPV_utxoresp *used,btc_tx *mtx,int64_t total,int3 else threshold = total; for (i=0; i threshold ) + if ( ptr[i].satoshis > threshold ) utxos[n++] = ptr[i]; + if ( n >= maxinputs ) + break; } remains = total; - //fprintf(stderr,"threshold %.8f n.%d for total %.8f\n",(double)threshold/COIN,n,(double)total/COIN); +//fprintf(stderr,"threshold %.8f n.%d num.%d for total %.8f, maxvins.%d NSPV_MAXVINS.%d\n",(double)threshold/COIN,num,n,(double)total/COIN,maxinputs,NSPV_MAXVINS); for (i=0; i0; i++) { below = above = 0; @@ -383,7 +385,7 @@ int64_t NSPV_addinputs(struct NSPV_utxoresp *used,btc_tx *mtx,int64_t total,int3 fprintf(stderr,"error finding unspent i.%d of %d, %.8f vs %.8f, abovei.%d belowi.%d ind.%d\n",i,n,(double)remains/COIN,(double)total/COIN,abovei,belowi,ind); return(0); } - //fprintf(stderr,"i.%d ind.%d abovei.%d belowi.%d n.%d\n",i,ind,abovei,belowi,n); +//fprintf(stderr,"i.%d ind.%d abovei.%d belowi.%d n.%d\n",i,ind,abovei,belowi,n); up = &utxos[ind]; btc_tx_add_txin(mtx,up->txid,up->vout); used[i] = *up; @@ -391,7 +393,7 @@ int64_t NSPV_addinputs(struct NSPV_utxoresp *used,btc_tx *mtx,int64_t total,int3 remains -= up->satoshis; utxos[ind] = utxos[--n]; memset(&utxos[n],0,sizeof(utxos[n])); - //fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs); +//fprintf(stderr,"totalinputs %.8f vs total %.8f i.%d vs max.%d\n",(double)totalinputs/COIN,(double)total/COIN,i,maxinputs); if ( totalinputs >= total || (i+1) >= maxinputs ) break; } @@ -424,12 +426,13 @@ bool NSPV_SignTx(btc_tx *mtx,int32_t vini,int64_t utxovalue,cstring *scriptPubKe sigerr = -1; else { - for (i=0; i<(int32_t)siglen; i++) - fprintf(stderr,"%02x",sig[i]); + // for (i=0; i<(int32_t)siglen; i++) + // fprintf(stderr,"%02x",sig[i]); vin = btc_tx_vin(mtx,vini); if ( scriptPubKey->len == 25 ) extralen = 34; else extralen = 0; + if (vin->script_sig) cstr_free(vin->script_sig,1); vin->script_sig = cstr_new_sz(siglen+2+extralen); vin->script_sig->str[0] = siglen+1; memcpy(vin->script_sig->str+1,sig,siglen); @@ -440,7 +443,7 @@ bool NSPV_SignTx(btc_tx *mtx,int32_t vini,int64_t utxovalue,cstring *scriptPubKe memcpy(vin->script_sig->str+2+siglen+1,NSPV_pubkey.pubkey,extralen-1); } vin->script_sig->len = siglen+2+extralen; - fprintf(stderr," sighash %s, sigerr.%d siglen.%d\n",bits256_str(str,sighash),sigerr,vin!=0?(int32_t)vin->script_sig->len:(int32_t)siglen); + //fprintf(stderr," sighash %s, sigerr.%d siglen.%d\n",bits256_str(str,sighash),sigerr,vin!=0?(int32_t)vin->script_sig->len:(int32_t)siglen); } return(true); } diff --git a/src/tools/nspv.c b/src/tools/nspv.c index ad7382b12..dd8d57349 100644 --- a/src/tools/nspv.c +++ b/src/tools/nspv.c @@ -120,7 +120,7 @@ void spv_sync_completed(btc_spv_client* client) { const btc_chainparams *NSPV_coinlist_scan(char *symbol,const btc_chainparams *template) { - btc_chainparams *chain = 0; char *filestr,*name,*seeds,*magic; int32_t i,n; cJSON *array,*coin; long filesize; + btc_chainparams *chain = 0; char *filestr,*name,*seeds,*magic=0; int32_t i,n; cJSON *array,*coin; long filesize; chain = calloc(1,sizeof(*chain)); memcpy(chain,template,sizeof(*chain)); chain->default_port = 0; @@ -137,14 +137,16 @@ const btc_chainparams *NSPV_coinlist_scan(char *symbol,const btc_chainparams *te //fprintf(stderr,"%s\n",jprint(coin,0)); if ( (name= jstr(coin,"coin")) != 0 && strcmp(name,symbol) == 0 && jstr(coin,"asset") != 0 ) { - if ( (seeds= jstr(coin,"nSPV")) != 0 && strlen(seeds) < sizeof(chain->dnsseeds[0].domain)-1 && (magic= jstr(coin,"magic")) != 0 && strlen(magic) == 8 ) + if ( (seeds= jstr(coin,"nSPV")) != 0 && strlen(seeds) < sizeof(chain->dnsseeds[0].domain)-1 && (magic=jstr(coin,"magic")) != 0 && strlen(magic) == 8 ) { if ( jstr(coin,"fname") != 0 ) strcpy(NSPV_fullname,jstr(coin,"fname")); chain->default_port = juint(coin,"p2p"); chain->rpcport = juint(coin,"rpcport"); strcpy(chain->dnsseeds[0].domain,seeds); - decode_hex((uint8_t *)chain->netmagic,4,magic); + char tmp[9]; + strcpy(tmp,magic); + decode_hex((uint8_t *)chain->netmagic,4,tmp); strcpy(chain->name,symbol); fprintf(stderr,"Found (%s) magic.%s, p2p.%u seeds.(%s)\n",symbol,magic,chain->default_port,seeds); break; @@ -156,7 +158,7 @@ const btc_chainparams *NSPV_coinlist_scan(char *symbol,const btc_chainparams *te free(chain); chain = 0; } - free(array); + cJSON_Delete(array); } else { @@ -296,7 +298,8 @@ int main(int argc, char* argv[]) fprintf(stderr," genesisblockhash %s\n",chain->name); data = (char *)"scan"; } - if ( OS_thread_create(malloc(sizeof(pthread_t)),NULL,NSPV_rpcloop,(void *)&port) != 0 ) + pthread_t thread; + if ( OS_thread_create(&thread,NULL,NSPV_rpcloop,(void *)&port) != 0 ) { printf("error launching NSPV_rpcloop for port.%u\n",port); exit(-1); @@ -364,6 +367,7 @@ int main(int argc, char* argv[]) btc_spv_client_runloop(client); printf("end of client runloop\n"); btc_spv_client_free(client); + pthread_cancel(thread); ret = EXIT_SUCCESS; } btc_ecc_stop(); @@ -373,5 +377,6 @@ int main(int argc, char* argv[]) printf("Invalid command (use -?)\n"); ret = EXIT_FAILURE; } + pthread_join(thread,NULL); return ret; }