/****************************************************************************** * Copyright © 2014-2017 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ // // LP_signatures.c // marketmaker // struct basilisk_request *LP_requestinit(struct basilisk_request *rp,bits256 srchash,bits256 desthash,char *src,uint64_t srcsatoshis,char *dest,uint64_t destsatoshis,uint32_t timestamp,uint32_t quotetime,int32_t DEXselector) { struct basilisk_request R; memset(rp,0,sizeof(*rp)); rp->srchash = srchash; rp->srcamount = srcsatoshis; rp->timestamp = timestamp; rp->DEXselector = DEXselector; safecopy(rp->src,src,sizeof(rp->src)); safecopy(rp->dest,dest,sizeof(rp->dest)); R = *rp; rp->requestid = basilisk_requestid(rp); rp->quotetime = quotetime; rp->desthash = desthash; rp->destamount = destsatoshis; rp->quoteid = basilisk_quoteid(rp); //printf("r.%u %u, q.%u %u: %s %.8f -> %s %.8f\n",rp->timestamp,rp->requestid,rp->quotetime,rp->quoteid,rp->src,dstr(rp->srcamount),rp->dest,dstr(rp->destamount)); return(rp); } cJSON *LP_quotejson(struct LP_quoteinfo *qp) { double price; cJSON *retjson = cJSON_CreateObject(); jaddstr(retjson,"gui",qp->gui[0] != 0 ? qp->gui : LP_gui); jadd64bits(retjson,"aliceid",qp->aliceid); jaddnum(retjson,"tradeid",qp->tradeid); jaddstr(retjson,"base",qp->srccoin); jaddstr(retjson,"rel",qp->destcoin); if ( qp->coinaddr[0] != 0 ) jaddstr(retjson,"address",qp->coinaddr); if ( qp->timestamp != 0 ) jaddnum(retjson,"timestamp",qp->timestamp); if ( bits256_nonz(qp->txid) != 0 ) { jaddbits256(retjson,"txid",qp->txid); jaddnum(retjson,"vout",qp->vout); } if ( bits256_nonz(qp->srchash) != 0 ) jaddbits256(retjson,"srchash",qp->srchash); if ( qp->txfee != 0 ) jadd64bits(retjson,"txfee",qp->txfee); if ( qp->quotetime != 0 ) jaddnum(retjson,"quotetime",qp->quotetime); if ( qp->satoshis != 0 ) jadd64bits(retjson,"satoshis",qp->satoshis); if ( bits256_nonz(qp->desthash) != 0 ) jaddbits256(retjson,"desthash",qp->desthash); if ( bits256_nonz(qp->txid2) != 0 ) { jaddbits256(retjson,"txid2",qp->txid2); jaddnum(retjson,"vout2",qp->vout2); } if ( bits256_nonz(qp->desttxid) != 0 ) { if ( qp->destaddr[0] != 0 ) jaddstr(retjson,"destaddr",qp->destaddr); jaddbits256(retjson,"desttxid",qp->desttxid); jaddnum(retjson,"destvout",qp->destvout); } if ( bits256_nonz(qp->feetxid) != 0 ) { jaddbits256(retjson,"feetxid",qp->feetxid); jaddnum(retjson,"feevout",qp->feevout); } if ( qp->desttxfee != 0 ) jadd64bits(retjson,"desttxfee",qp->desttxfee); if ( qp->destsatoshis != 0 ) { jadd64bits(retjson,"destsatoshis",qp->destsatoshis); if ( qp->satoshis != 0 ) { price = (double)qp->destsatoshis / (qp->satoshis - qp->txfee); jaddnum(retjson,"price",price); } } if ( qp->R.requestid != 0 ) jaddnum(retjson,"requestid",qp->R.requestid); if ( qp->R.quoteid != 0 ) jaddnum(retjson,"quoteid",qp->R.quoteid); return(retjson); } int32_t LP_quoteparse(struct LP_quoteinfo *qp,cJSON *argjson) { uint32_t rid,qid; memset(qp,0,sizeof(*qp)); safecopy(qp->gui,LP_gui,sizeof(qp->gui)); safecopy(qp->srccoin,jstr(argjson,"base"),sizeof(qp->srccoin)); safecopy(qp->coinaddr,jstr(argjson,"address"),sizeof(qp->coinaddr)); safecopy(qp->destcoin,jstr(argjson,"rel"),sizeof(qp->destcoin)); safecopy(qp->destaddr,jstr(argjson,"destaddr"),sizeof(qp->destaddr)); qp->aliceid = j64bits(argjson,"aliceid"); qp->tradeid = juint(argjson,"tradeid"); qp->timestamp = juint(argjson,"timestamp"); qp->quotetime = juint(argjson,"quotetime"); qp->txid = jbits256(argjson,"txid"); qp->txid2 = jbits256(argjson,"txid2"); qp->vout = jint(argjson,"vout"); qp->vout2 = jint(argjson,"vout2"); qp->feevout = jint(argjson,"feevout"); qp->srchash = jbits256(argjson,"srchash"); qp->desttxid = jbits256(argjson,"desttxid"); qp->feetxid = jbits256(argjson,"feetxid"); qp->destvout = jint(argjson,"destvout"); qp->desthash = jbits256(argjson,"desthash"); qp->satoshis = j64bits(argjson,"satoshis"); qp->destsatoshis = j64bits(argjson,"destsatoshis"); qp->txfee = j64bits(argjson,"txfee"); qp->desttxfee = j64bits(argjson,"desttxfee"); qp->R.requestid = juint(argjson,"requestid"); qp->R.quoteid = juint(argjson,"quoteid"); if ( qp->R.requestid == 0 ) { rid = basilisk_requestid(&qp->R); if ( qp->R.requestid != 0 && qp->R.requestid != rid ) printf("requestid.%u -> %u\n",qp->R.requestid,rid); qp->R.requestid = rid; } if ( qp->R.quoteid == 0 ) { qid = basilisk_quoteid(&qp->R); if ( qp->R.quoteid != 0 && qp->R.quoteid != qid ) printf("quoteid.%u -> %u\n",qp->R.quoteid,qid); qp->R.quoteid = qid; } return(0); } void LP_txfees(uint64_t *txfeep,uint64_t *desttxfeep,char *base,char *rel) { *txfeep = LP_txfeecalc(LP_coinfind(base),0,0); *desttxfeep = LP_txfeecalc(LP_coinfind(rel),0,0); //printf("LP_txfees(%.8f %.8f)\n",dstr(*txfeep),dstr(*desttxfeep)); } int32_t LP_quoteinfoinit(struct LP_quoteinfo *qp,struct LP_utxoinfo *utxo,char *destcoin,double price,uint64_t satoshis,uint64_t destsatoshis) { memset(qp,0,sizeof(*qp)); if ( qp->timestamp == 0 ) qp->timestamp = (uint32_t)time(NULL); safecopy(qp->destcoin,destcoin,sizeof(qp->destcoin)); LP_txfees(&qp->txfee,&qp->desttxfee,utxo->coin,qp->destcoin); qp->satoshis = satoshis;//(destsatoshis / price) + 0.49; qp->destsatoshis = destsatoshis; /*if ( qp->txfee >= qp->satoshis || qp->txfee >= utxo->deposit.value || utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis) ) //utxo->iambob == 0 || { printf("quoteinit error.(%d %d %d %d) %.8f vs %.8f\n",utxo->iambob == 0,qp->txfee >= qp->satoshis,qp->txfee >= utxo->deposit.value,utxo->deposit.value < LP_DEPOSITSATOSHIS(qp->satoshis),dstr(utxo->deposit.value),dstr(LP_DEPOSITSATOSHIS(qp->satoshis))); return(-1); }*/ qp->txid = utxo->payment.txid; qp->vout = utxo->payment.vout; qp->txid2 = utxo->deposit.txid; qp->vout2 = utxo->deposit.vout; if ( qp->desttxfee >= qp->destsatoshis ) { printf("quoteinit desttxfee %.8f < %.8f destsatoshis\n",dstr(qp->desttxfee),dstr(qp->destsatoshis)); return(-2); } safecopy(qp->srccoin,utxo->coin,sizeof(qp->srccoin)); safecopy(qp->coinaddr,utxo->coinaddr,sizeof(qp->coinaddr)); qp->srchash = utxo->pubkey; return(0); } int32_t LP_quotedestinfo(struct LP_quoteinfo *qp,bits256 desttxid,int32_t destvout,bits256 feetxid,int32_t feevout,bits256 desthash,char *destaddr) { qp->desttxid = desttxid; qp->destvout = destvout; qp->desthash = desthash; qp->feetxid = feetxid; qp->feevout = feevout; safecopy(qp->destaddr,destaddr,sizeof(qp->destaddr)); return(0); } char *LP_quotereceived(cJSON *argjson) { struct LP_cacheinfo *ptr; double price; struct LP_quoteinfo Q; LP_quoteparse(&Q,argjson); price = (double)Q.destsatoshis / (Q.satoshis - Q.txfee); if ( (ptr= LP_cacheadd(Q.srccoin,Q.destcoin,Q.txid,Q.vout,price,&Q)) != 0 ) { ptr->Q = Q; printf(">>>>>>>>>> received quote %s/%s %.8f\n",Q.srccoin,Q.destcoin,price); return(clonestr("{\"result\":\"updated\"}")); } else return(clonestr("{\"error\":\"nullptr\"}")); } int32_t LP_bitcoinsig_add(cJSON *item,bits256 priv,uint8_t *pubsecp,bits256 sighash) { static void *ctx; int32_t i,j,siglen; uint8_t pub33[33],sig[65]; char sigstr[256]; if ( ctx == 0 ) ctx = bitcoin_ctx(); for (j=0; j<100; j++) { if ( (siglen= bitcoin_sign(ctx,"sigadd",sig,sighash,priv,1)) > 0 && siglen == 65 ) { memset(pub33,0,33); if ( bitcoin_recoververify(ctx,"test",sig,sighash,pub33,0) == 0 && memcmp(pub33,pubsecp,33) == 0 ) { init_hexbytes_noT(sigstr,sig,siglen); jaddstr(item,"sig",sigstr); return(siglen); } if ( 0 ) { for (i=0; i<33; i++) printf("%02x",pubsecp[i]); printf(" pubsecp -> "); for (i=0; i<33; i++) printf("%02x",pub33[i]); printf(" mismatched recovered pubkey.%d of %d\n",j,100); } } } return(-1); } bits256 LP_price_sighash(uint32_t timestamp,uint8_t *pubsecp,bits256 pubkey,char *base,char *rel,uint64_t price64) { uint8_t buf[sizeof(pubkey) + 33 + sizeof(uint64_t)*3 + sizeof(timestamp)]; uint64_t basebits,relbits; bits256 sighash; basebits = stringbits(base); relbits = stringbits(rel); memcpy(buf,pubkey.bytes,sizeof(pubkey)); memcpy(&buf[sizeof(pubkey)],pubsecp,33); memcpy(&buf[sizeof(pubkey)+33],&price64,sizeof(price64)); memcpy(&buf[sizeof(pubkey)+33+sizeof(price64)],&basebits,sizeof(basebits)); memcpy(&buf[sizeof(pubkey)+33+sizeof(price64)+sizeof(basebits)],&relbits,sizeof(relbits)); memcpy(&buf[sizeof(pubkey)+33+sizeof(price64)+sizeof(basebits)+sizeof(relbits)],×tamp,sizeof(timestamp)); vcalc_sha256(0,sighash.bytes,buf,sizeof(buf)); return(sighash); } bits256 LP_pubkey_sighash(uint32_t timestamp,bits256 pubkey,uint8_t *rmd160,uint8_t *pubsecp) { uint8_t buf[sizeof(pubkey) + 20 + 33 + sizeof(timestamp)]; bits256 sighash; memcpy(buf,pubkey.bytes,sizeof(pubkey)); memcpy(&buf[sizeof(pubkey)],rmd160,20); memcpy(&buf[sizeof(pubkey)+20],pubsecp,33); memcpy(&buf[sizeof(pubkey)+20+33],×tamp,sizeof(timestamp)); vcalc_sha256(0,sighash.bytes,buf,sizeof(buf)); return(sighash); } bits256 LP_utxos_sighash(uint32_t timestamp,uint8_t *pubsecp,bits256 pubkey,bits256 utxoshash) { uint8_t buf[sizeof(pubkey)+sizeof(utxoshash)+33+sizeof(timestamp)]; bits256 sighash; memcpy(buf,pubkey.bytes,sizeof(pubkey)); memcpy(&buf[sizeof(pubkey)],pubsecp,33); memcpy(&buf[sizeof(pubkey)+33],×tamp,sizeof(timestamp)); memcpy(&buf[sizeof(pubkey)+33+sizeof(timestamp)],utxoshash.bytes,sizeof(utxoshash)); vcalc_sha256(0,sighash.bytes,buf,sizeof(buf)); return(sighash); } int32_t LP_utxos_sigcheck(uint32_t timestamp,char *sigstr,char *pubsecpstr,bits256 pubkey,bits256 utxoshash) { static void *ctx; int32_t retval=-1; uint8_t pub33[33],pubsecp[33],sig[65]; bits256 sighash; char str[65]; struct LP_pubkey_info *pubp; if ( ctx == 0 ) ctx = bitcoin_ctx(); pubp = LP_pubkeyfind(pubkey); if ( (pubp == 0 || pubp->numerrors < LP_MAXPUBKEY_ERRORS) && sigstr != 0 && pubsecpstr != 0 && strlen(sigstr) == 65*2 && strlen(pubsecpstr) == 33 *2 ) { decode_hex(sig,65,sigstr); decode_hex(pubsecp,33,pubsecpstr); sighash = LP_utxos_sighash(timestamp,pubsecp,pubkey,utxoshash); retval = bitcoin_recoververify(ctx,"utxos",sig,sighash,pub33,0); if ( memcmp(pub33,pubsecp,33) != 0 || retval != 0 ) { static uint32_t counter; if ( counter++ <= LP_MAXPUBKEY_ERRORS ) { if ( pubp != 0 ) pubp->numerrors++; if ( pubp != 0 && pubp->numerrors > LP_MAXPUBKEY_ERRORS/2 ) printf("LP_utxos_sigcheck failure.%d, probably from %s with older version\n",pubp!=0?pubp->numerrors:-1,bits256_str(str,pubkey)); } retval = -1; } else retval = 0; } return(retval); } bits256 LP_utxoshash_calc(cJSON *array) { int32_t i,j,n; bits256 utxoshash,txid; cJSON *item; memset(utxoshash.bytes,0,sizeof(utxoshash)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; ismartaddr); if ( cJSON_GetArraySize(array) == 0 ) free_json(array); else { memset(zero.bytes,0,sizeof(zero)); jaddstr(reqjson,"method","postutxos"); jaddstr(reqjson,"coin",symbol); jaddstr(reqjson,"coinaddr",coinaddr); jadd(reqjson,"utxos",array); timestamp = (uint32_t)time(NULL); jaddnum(reqjson,"timetamp",timestamp); init_hexbytes_noT(pubsecpstr,G.LP_pubsecp,33); jaddstr(reqjson,"pubsecp",pubsecpstr); jaddbits256(reqjson,"pubkey",G.LP_mypub25519); utxoshash = LP_utxoshash_calc(array); //char str[65]; printf("utxoshash add %s\n",bits256_str(str,utxoshash)); LP_utxos_sigadd(reqjson,timestamp,G.LP_privkey,G.LP_pubsecp,G.LP_mypub25519,utxoshash); //printf("post (%s) -> %d\n",msg,LP_mypubsock); LP_reserved_msg(0,symbol,symbol,zero,jprint(reqjson,1)); } } } queue_t utxosQ; struct LP_utxos_qitem { struct queueitem DL; cJSON *argjson; }; char *LP_postutxos_recv(cJSON *argjson) { struct LP_utxos_qitem *uitem; struct iguana_info *coin; char *coinaddr,*symbol; bits256 utxoshash,pubkey; cJSON *obj; struct LP_pubkey_info *pubp; printf("LP_postutxos_recv deprecated\n"); pubkey = jbits256(argjson,"pubkey"); pubp = LP_pubkeyfind(pubkey); if ( pubp != 0 && pubp->numerrors > LP_MAXPUBKEY_ERRORS ) return(clonestr("{\"error\":\"blacklisted\"}")); if ( (coinaddr= jstr(argjson,"coinaddr")) != 0 && (symbol= jstr(argjson,"coin")) != 0 && (coin= LP_coinfind(symbol)) != 0 ) { if ( strcmp(coinaddr,coin->smartaddr) == 0 ) { //printf("ignore my utxo from external source %s %s\n",symbol,coinaddr); return(clonestr("{\"result\":\"success\"}")); } } if ( (obj= jobj(argjson,"utxos")) != 0 ) { utxoshash = LP_utxoshash_calc(obj); //char str[65]; //printf("got utxoshash %s\n",bits256_str(str,utxoshash)); if ( LP_utxos_sigcheck(juint(argjson,"timestamp"),jstr(argjson,"sig"),jstr(argjson,"pubsecp"),pubkey,utxoshash) == 0 ) { uitem = calloc(1,sizeof(*uitem)); uitem->argjson = jduplicate(argjson); queue_enqueue("utxosQ",&utxosQ,&uitem->DL); return(clonestr("{\"result\":\"success\"}")); } //else printf("valid utxos sig %s\n",bits256_str(str,pubp->pubkey)); } return(clonestr("{\"error\":\"sig failure\"}")); } int32_t LP_utxosQ_process() { struct LP_utxos_qitem *uitem; int32_t n; char *symbol,*coinaddr; struct LP_address *ap; struct iguana_info *coin; cJSON *array; if ( (uitem= queue_dequeue(&utxosQ)) != 0 ) { //printf("LP_utxosQ_process.(%s)\n",jprint(uitem->argjson,0)); if ( (coinaddr= jstr(uitem->argjson,"coinaddr")) != 0 && (symbol= jstr(uitem->argjson,"coin")) != 0 && (coin= LP_coinfind(symbol)) != 0 ) // addsig { if ( coin->electrum == 0 || (ap= LP_addressfind(coin,coinaddr)) != 0 ) { if ( (array= jarray(&n,uitem->argjson,"utxos")) != 0 ) LP_unspents_array(coin,coinaddr,array); } else if ( (array= electrum_address_listunspent(symbol,coin->electrum,&array,coinaddr,1)) != 0 ) free_json(array); } free_json(uitem->argjson); free(uitem); return(1); } return(0); } int32_t LP_price_sigcheck(uint32_t timestamp,char *sigstr,char *pubsecpstr,bits256 pubkey,char *base,char *rel,uint64_t price64) { static void *ctx; int32_t retval=-1; uint8_t pub33[33],pubsecp[33],sig[65]; bits256 sighash; struct LP_pubkey_info *pubp; if ( ctx == 0 ) ctx = bitcoin_ctx(); pubp = LP_pubkeyfind(pubkey); if ( (pubp == 0 || pubp->numerrors < LP_MAXPUBKEY_ERRORS) && sigstr != 0 && pubsecpstr != 0 && strlen(sigstr) == 65*2 && strlen(pubsecpstr) == 33 *2 ) { decode_hex(sig,65,sigstr); decode_hex(pubsecp,33,pubsecpstr); sighash = LP_price_sighash(timestamp,pubsecp,pubkey,base,rel,price64); retval = bitcoin_recoververify(ctx,"price",sig,sighash,pub33,0); if ( memcmp(pub33,pubsecp,33) != 0 || retval != 0 ) { if ( pubp != 0 ) pubp->numerrors++; printf("LP_price_sigcheck failure\n"); retval = -1; } else { retval = 0; //printf("valid price sig %s/%s %.8f\n",base,rel,dstr(price64)); } } return(retval); } int32_t LP_price_sigadd(cJSON *item,uint32_t timestamp,bits256 priv,uint8_t *pubsecp,bits256 pubkey,char *base,char *rel,uint64_t price64) { bits256 sighash; sighash = LP_price_sighash(timestamp,pubsecp,pubkey,base,rel,price64); return(LP_bitcoinsig_add(item,priv,pubsecp,sighash)); } char *LP_pricepings(void *ctx,char *myipaddr,int32_t pubsock,char *base,char *rel,double price) { struct iguana_info *basecoin,*relcoin; char pubsecpstr[67]; uint32_t numutxos,timestamp; uint64_t price64,balance,minsize,maxsize; bits256 zero; cJSON *reqjson; reqjson = cJSON_CreateObject(); // LP_addsig if ( (basecoin= LP_coinfind(base)) != 0 && (relcoin= LP_coinfind(rel)) != 0 )//&& basecoin->electrum == 0 )//&& relcoin->electrum == 0 ) { memset(zero.bytes,0,sizeof(zero)); jaddbits256(reqjson,"pubkey",G.LP_mypub25519); jaddstr(reqjson,"base",base); jaddstr(reqjson,"rel",rel); price64 = price * SATOSHIDEN + 0.0000000049; jaddnum(reqjson,"price",price); jadd64bits(reqjson,"price64",price64); jaddstr(reqjson,"method","postprice"); timestamp = (uint32_t)time(NULL); jaddnum(reqjson,"timestamp",timestamp); init_hexbytes_noT(pubsecpstr,G.LP_pubsecp,33); jaddstr(reqjson,"pubsecp",pubsecpstr); //if ( (ap= LP_address(basecoin,basecoin->smartaddr)) != 0 ) { if ( (numutxos= LP_address_minmax(&balance,&minsize,&maxsize,basecoin,basecoin->smartaddr)) != 0 ) { //printf("send %s numutxos.%d balance %.8f min %.8f max %.8f\n",base,numutxos,dstr(balance),dstr(minsize),dstr(maxsize)); jaddstr(reqjson,"utxocoin",base); jaddnum(reqjson,"n",numutxos); jaddnum(reqjson,"bal",dstr(balance)); jaddnum(reqjson,"min",dstr(minsize)); jaddnum(reqjson,"max",dstr(maxsize)); } } LP_price_sigadd(reqjson,timestamp,G.LP_privkey,G.LP_pubsecp,G.LP_mypub25519,base,rel,price64); LP_reserved_msg(0,base,rel,zero,jprint(reqjson,1)); return(clonestr("{\"result\":\"success\"}")); } else return(clonestr("{\"error\":\"electrum node cant post bob asks\"}")); } char *LP_postprice_recv(cJSON *argjson) { bits256 pubkey; double price; char *base,*rel; //printf("PRICE POSTED.(%s)\n",jprint(argjson,0)); if ( (base= jstr(argjson,"base")) != 0 && (rel= jstr(argjson,"rel")) != 0 && (price= jdouble(argjson,"price")) > SMALLVAL ) { pubkey = jbits256(argjson,"pubkey"); if ( bits256_nonz(pubkey) != 0 ) { if ( LP_price_sigcheck(juint(argjson,"timestamp"),jstr(argjson,"sig"),jstr(argjson,"pubsecp"),pubkey,base,rel,j64bits(argjson,"price64")) == 0 ) { //printf("call pricefeed update\n"); LP_pricefeedupdate(pubkey,base,rel,price,jstr(argjson,"utxocoin"),jint(argjson,"n"),jdouble(argjson,"bal")*SATOSHIDEN,jdouble(argjson,"min")*SATOSHIDEN,jdouble(argjson,"max")*SATOSHIDEN); return(clonestr("{\"result\":\"success\"}")); } else { printf("sig failure\n"); return(clonestr("{\"error\":\"sig failure\"}")); } } } return(clonestr("{\"error\":\"missing fields in posted price\"}")); } int32_t _LP_pubkey_sigcheck(uint8_t *sig,int32_t siglen,uint32_t timestamp,bits256 pub,uint8_t *rmd160,uint8_t *pubsecp) { static void *ctx; uint8_t pub33[33]; bits256 sighash; if ( ctx == 0 ) ctx = bitcoin_ctx(); sighash = LP_pubkey_sighash(timestamp,pub,rmd160,pubsecp); return(bitcoin_recoververify(ctx,"pubkey",sig,sighash,pub33,0)); } int32_t LP_pubkey_sigadd(cJSON *item,uint32_t timestamp,bits256 priv,bits256 pub,uint8_t *rmd160,uint8_t *pubsecp) { bits256 sighash; sighash = LP_pubkey_sighash(timestamp,pub,rmd160,pubsecp); return(LP_bitcoinsig_add(item,priv,pubsecp,sighash)); } int32_t LP_pubkey_sigcheck(struct LP_pubkey_info *pubp,cJSON *item) { int32_t i,len,siglen,retval=-1; uint8_t rmd160[20],checkrmd160[20],pubsecp[33],sig[65],zeroes[20]; char *sigstr,*hexstr,*pubsecpstr; if ( (hexstr= jstr(item,"rmd160")) != 0 && strlen(hexstr) == 2*sizeof(rmd160) ) { decode_hex(rmd160,sizeof(rmd160),hexstr); memset(zeroes,0,sizeof(zeroes)); if ( memcmp(zeroes,rmd160,sizeof(rmd160)) != 0 ) { //if ( memcmp(rmd160,pubp->rmd160,20) != 0 ) { if ( (pubsecpstr= jstr(item,"pubsecp")) != 0 && is_hexstr(pubsecpstr,0) == 66 ) { decode_hex(pubsecp,sizeof(pubsecp),pubsecpstr); calc_rmd160_sha256(checkrmd160,pubsecp,33); if ( memcmp(checkrmd160,rmd160,20) == 0 ) { if ( (sigstr= jstr(item,"sig")) != 0 && (len= is_hexstr(sigstr,0)) == 65*2 ) { siglen = len >> 1; decode_hex(sig,siglen,sigstr); if ( _LP_pubkey_sigcheck(sig,siglen,juint(item,"timestamp"),pubp->pubkey,rmd160,pubsecp) == 0 ) { if ( memcmp(rmd160,pubp->rmd160,20) != 0 ) { //for (i=0; i<20; i++) // printf("%02x",pubp->rmd160[i]); memcpy(pubp->rmd160,rmd160,sizeof(pubp->rmd160)); memcpy(pubp->pubsecp,pubsecp,sizeof(pubp->pubsecp)); memcpy(pubp->sig,sig,sizeof(pubp->sig)); pubp->siglen = siglen; //char str[65]; printf(" -> rmd160.(%s) for %s (%s) sig.%s\n",hexstr,bits256_str(str,pubp->pubkey),pubsecpstr,sigstr); } pubp->timestamp = juint(item,"timestamp"); retval = 0; } else pubp->numerrors++; } } else if ( 0 ) { for (i=0; i<20; i++) printf("%02x",rmd160[i]); printf(" rmd160 vs "); for (i=0; i<20; i++) printf("%02x",checkrmd160[i]); printf(" for %s\n",pubsecpstr); } } } } } return(retval); } void LP_notify_pubkeys(void *ctx,int32_t pubsock) { bits256 zero; uint32_t timestamp; char LPipaddr[64],secpstr[67]; cJSON *reqjson = cJSON_CreateObject(); memset(zero.bytes,0,sizeof(zero)); jaddstr(reqjson,"method","notify"); jaddstr(reqjson,"rmd160",G.LP_myrmd160str); jaddbits256(reqjson,"pub",G.LP_mypub25519); init_hexbytes_noT(secpstr,G.LP_pubsecp,33); jaddstr(reqjson,"pubsecp",secpstr); timestamp = (uint32_t)time(NULL); jaddnum(reqjson,"timestamp",timestamp); LP_pubkey_sigadd(reqjson,timestamp,G.LP_privkey,G.LP_mypub25519,G.LP_myrmd160,G.LP_pubsecp); if ( IAMLP != 0 ) { if ( LP_rarestpeer(LPipaddr) != 0 ) { jaddstr(reqjson,"isLP",LPipaddr); if ( strcmp(LPipaddr,LP_myipaddr) == 0 ) jaddnum(reqjson,"ismine",1); } else printf("no LPipaddr\n"); } jaddnum(reqjson,"session",G.LP_sessionid); LP_reserved_msg(0,"","",zero,jprint(reqjson,1)); } char *LP_notify_recv(cJSON *argjson) { bits256 pub; struct LP_pubkey_info *pubp; char *ipaddr; pub = jbits256(argjson,"pub"); if ( bits256_nonz(pub) != 0 ) { if ( (pubp= LP_pubkeyadd(pub)) != 0 ) LP_pubkey_sigcheck(pubp,argjson); if ( (ipaddr= jstr(argjson,"isLP")) != 0 ) { //printf("notify got isLP %s %d\n",ipaddr,jint(argjson,"ismine")); LP_peer_recv(ipaddr,jint(argjson,"ismine")); if ( IAMLP != 0 && G.LP_IAMLP == 0 && strcmp(ipaddr,LP_myipaddr) == 0 ) { if ( bits256_cmp(pub,G.LP_mypub25519) != 0 ) { char str[65]; printf("that's me! and it is from %s which isnt me\n",bits256_str(str,pub)); G.LP_IAMLP = 1; } } LP_addpeer(LP_mypeer,LP_mypubsock,ipaddr,RPC_port,RPC_port+10,RPC_port+20,1,juint(argjson,"session")); } //char str[65]; printf("%.3f NOTIFIED pub %s rmd160 %s\n",OS_milliseconds()-millis,bits256_str(str,pub),rmd160str); } return(clonestr("{\"result\":\"success\",\"notify\":\"received\"}")); } void LP_smartutxos_push(struct iguana_info *coin) { uint64_t value; bits256 zero,txid; int32_t i,vout,height,n; cJSON *array,*item,*req; return; if ( coin->smartaddr[0] == 0 ) return; //LP_notify_pubkeys(coin->ctx,LP_mypubsock); if ( (array= LP_address_utxos(coin,coin->smartaddr,1)) != 0 ) { memset(zero.bytes,0,sizeof(zero)); if ( (n= cJSON_GetArraySize(array)) > 0 ) { //printf("PUSH %s %s\n",coin->symbol,coin->smartaddr); for (i=0; isymbol); jaddstr(req,"coinaddr",coin->smartaddr); jaddbits256(req,"txid",txid); jaddnum(req,"vout",vout); jaddnum(req,"ht",height); jadd64bits(req,"value",value); //printf("ADDR_UNSPENTS[] <- %s\n",jprint(req,0)); LP_reserved_msg(0,"","",zero,jprint(req,1)); } } free_json(array); } } char *LP_uitem_recv(cJSON *argjson) { bits256 txid; int32_t vout,height; uint64_t value; struct iguana_info *coin; char *coinaddr,*symbol; printf("LP_uitem_recv deprecated\n"); txid = jbits256(argjson,"txid"); vout = jint(argjson,"vout"); height = jint(argjson,"ht"); value = j64bits(argjson,"value"); coinaddr = jstr(argjson,"coinaddr"); if ( (symbol= jstr(argjson,"coin")) != 0 && coinaddr != 0 && (coin= LP_coinfind(symbol)) != 0 ) { //char str[65]; printf("uitem %s %s %s/v%d %.8f ht.%d\n",symbol,coinaddr,bits256_str(str,txid),vout,dstr(value),height); if ( strcmp(coin->smartaddr,coinaddr) != 0 ) LP_address_utxoadd((uint32_t)time(NULL),"LP_uitem_recv",coin,coinaddr,txid,vout,value,height,-1); //else printf("ignore external uitem %s %s\n",symbol,coin->smartaddr); } return(clonestr("{\"result\":\"success\"}")); } void LP_listunspent_query(char *symbol,char *coinaddr) { bits256 zero; cJSON *reqjson = cJSON_CreateObject(); memset(zero.bytes,0,sizeof(zero)); jaddstr(reqjson,"method","addr_unspents"); jaddstr(reqjson,"coin",symbol); jaddstr(reqjson,"address",coinaddr); LP_reserved_msg(0,"","",zero,jprint(reqjson,1)); } void LP_query(void *ctx,char *myipaddr,int32_t mypubsock,char *method,struct LP_quoteinfo *qp) { cJSON *reqjson; bits256 zero; char *msg; int32_t flag = 0; if ( strcmp(method,"request") == 0 ) { if ( LP_allocated(qp->desttxid,qp->destvout) == 0 && LP_allocated(qp->feetxid,qp->feevout) == 0 ) { LP_unavailableset(qp->desttxid,qp->destvout,qp->timestamp+LP_AUTOTRADE_TIMEOUT*4,qp->srchash); LP_unavailableset(qp->feetxid,qp->feevout,qp->timestamp+LP_AUTOTRADE_TIMEOUT*4,qp->srchash); } else { printf("couldnt find my txid to make request\n"); return; } } reqjson = LP_quotejson(qp); if ( bits256_nonz(qp->desthash) != 0 ) flag = 1; jaddbits256(reqjson,"pubkey",qp->srchash); jaddstr(reqjson,"method",method); if ( jobj(reqjson,"timestamp") == 0 ) jaddnum(reqjson,"timestamp",time(NULL)); msg = jprint(reqjson,1); printf("QUERY.(%s)\n",msg); if ( bits256_nonz(qp->srchash) == 0 || strcmp(method,"request") != 0 ) { memset(&zero,0,sizeof(zero)); LP_reserved_msg(1,qp->srccoin,qp->destcoin,qp->desthash,clonestr(msg)); LP_reserved_msg(1,qp->srccoin,qp->destcoin,zero,clonestr(msg)); LP_reserved_msg(0,qp->srccoin,qp->destcoin,zero,clonestr(msg)); free(msg); /*portable_mutex_lock(&LP_reservedmutex); if ( num_Reserved_msgs[1] < sizeof(Reserved_msgs[1])/sizeof(*Reserved_msgs[1])-2 ) Reserved_msgs[1][num_Reserved_msgs[1]++] = msg; if ( num_Reserved_msgs[0] < sizeof(Reserved_msgs[0])/sizeof(*Reserved_msgs[0])-2 ) Reserved_msgs[0][num_Reserved_msgs[0]++] = msg2; portable_mutex_unlock(&LP_reservedmutex);*/ } else LP_broadcast_message(LP_mypubsock,qp->srccoin,qp->destcoin,qp->srchash,msg); }