// Copyright (c) 2016-2024 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #ifndef HUSH_NSPVSUPERLITE_H #define HUSH_NSPVSUPERLITE_H // nSPV client. VERY simplistic "single threaded" networking model. for production GUI best to multithread, etc. // no caching, no optimizations, no reducing the number of ntzsproofs needed by detecting overlaps, etc. // advantage is that it is simpler to implement and understand to create a design for a more performant version CAmount AmountFromValue(const UniValue& value); int32_t bitcoin_base58decode(uint8_t *data,char *coinaddr); uint32_t NSPV_lastinfo,NSPV_logintime,NSPV_tiptime; CKey NSPV_key; char NSPV_wifstr[64],NSPV_pubkeystr[67],NSPV_lastpeer[128]; std::string NSPV_address; struct NSPV_inforesp NSPV_inforesult; struct NSPV_utxosresp NSPV_utxosresult; struct NSPV_txidsresp NSPV_txidsresult; struct NSPV_mempoolresp NSPV_mempoolresult; struct NSPV_spentinfo NSPV_spentresult; struct NSPV_ntzsresp NSPV_ntzsresult; struct NSPV_ntzsproofresp NSPV_ntzsproofresult; struct NSPV_txproof NSPV_txproofresult; struct NSPV_broadcastresp NSPV_broadcastresult; struct NSPV_ntzsresp NSPV_ntzsresp_cache[NSPV_MAXVINS]; struct NSPV_ntzsproofresp NSPV_ntzsproofresp_cache[NSPV_MAXVINS * 2]; struct NSPV_txproof NSPV_txproof_cache[NSPV_MAXVINS * 4]; struct NSPV_ntzsresp *NSPV_ntzsresp_find(int32_t reqheight) { int32_t i; for (i=0; ireqheight); return(&NSPV_ntzsresp_cache[i]); } struct NSPV_txproof *NSPV_txproof_find(uint256 txid) { int32_t i; struct NSPV_txproof *backup = 0; for (i=0; itxid ) { if ( NSPV_txproof_cache[i].txprooflen == 0 && ptr->txprooflen != 0 ) { NSPV_txproof_purge(&NSPV_txproof_cache[i]); NSPV_txproof_copy(&NSPV_txproof_cache[i],ptr); return(&NSPV_txproof_cache[i]); } else if ( NSPV_txproof_cache[i].txprooflen != 0 || ptr->txprooflen == 0 ) return(&NSPV_txproof_cache[i]); } for (i=0; itxid.GetHex().c_str()); return(&NSPV_txproof_cache[i]); } struct NSPV_ntzsproofresp *NSPV_ntzsproof_find(uint256 prevtxid,uint256 nexttxid) { int32_t i; for (i=0; iprevtxid.GetHex().c_str(),ptr->nexttxid.GetHex().c_str()); return(&NSPV_ntzsproofresp_cache[i]); } // hush_nSPVresp is called from async message processing void hush_nSPVresp(CNode *pfrom,std::vector response) // received a response { struct NSPV_inforesp I; int32_t len; uint32_t timestamp = (uint32_t)time(NULL); strncpy(NSPV_lastpeer,pfrom->addr.ToString().c_str(),sizeof(NSPV_lastpeer)-1); if ( (len= response.size()) > 0 ) { switch ( response[0] ) { case NSPV_INFORESP: fprintf(stderr,"got version.%d info response %u size.%d height.%d\n",NSPV_inforesult.version,timestamp,(int32_t)response.size(),NSPV_inforesult.height); // update current height and ntrz status I = NSPV_inforesult; NSPV_inforesp_purge(&NSPV_inforesult); NSPV_rwinforesp(0,&response[1],&NSPV_inforesult); if ( NSPV_inforesult.height < I.height ) { fprintf(stderr,"got old info response %u size.%d height.%d\n",timestamp,(int32_t)response.size(),NSPV_inforesult.height); // update current height and ntrz status NSPV_inforesp_purge(&NSPV_inforesult); NSPV_inforesult = I; } else if ( NSPV_inforesult.height > I.height ) { NSPV_lastinfo = timestamp - ASSETCHAINS_BLOCKTIME/4; // need to validate new header to make sure it is valid mainchain if ( NSPV_inforesult.height == NSPV_inforesult.hdrheight ) NSPV_tiptime = NSPV_inforesult.H.nTime; } break; case NSPV_UTXOSRESP: NSPV_utxosresp_purge(&NSPV_utxosresult); NSPV_rwutxosresp(0,&response[1],&NSPV_utxosresult); fprintf(stderr,"got utxos response %u size.%d\n",timestamp,(int32_t)response.size()); break; case NSPV_TXIDSRESP: NSPV_txidsresp_purge(&NSPV_txidsresult); NSPV_rwtxidsresp(0,&response[1],&NSPV_txidsresult); fprintf(stderr,"got txids response %u size.%d %s CC.%d num.%d\n",timestamp,(int32_t)response.size(),NSPV_txidsresult.coinaddr,NSPV_txidsresult.CCflag,NSPV_txidsresult.numtxids); break; case NSPV_MEMPOOLRESP: NSPV_mempoolresp_purge(&NSPV_mempoolresult); NSPV_rwmempoolresp(0,&response[1],&NSPV_mempoolresult); fprintf(stderr,"got mempool response %u size.%d %s CC.%d num.%d funcid.%d %s/v%d\n",timestamp,(int32_t)response.size(),NSPV_mempoolresult.coinaddr,NSPV_mempoolresult.CCflag,NSPV_mempoolresult.numtxids,NSPV_mempoolresult.funcid,NSPV_mempoolresult.txid.GetHex().c_str(),NSPV_mempoolresult.vout); break; case NSPV_NTZSRESP: NSPV_ntzsresp_purge(&NSPV_ntzsresult); NSPV_rwntzsresp(0,&response[1],&NSPV_ntzsresult); if ( NSPV_ntzsresp_find(NSPV_ntzsresult.reqheight) == 0 ) NSPV_ntzsresp_add(&NSPV_ntzsresult); fprintf(stderr,"got ntzs response %u size.%d %s prev.%d, %s next.%d\n",timestamp,(int32_t)response.size(),NSPV_ntzsresult.prevntz.txid.GetHex().c_str(),NSPV_ntzsresult.prevntz.height,NSPV_ntzsresult.nextntz.txid.GetHex().c_str(),NSPV_ntzsresult.nextntz.height); break; case NSPV_NTZSPROOFRESP: NSPV_ntzsproofresp_purge(&NSPV_ntzsproofresult); NSPV_rwntzsproofresp(0,&response[1],&NSPV_ntzsproofresult); if ( NSPV_ntzsproof_find(NSPV_ntzsproofresult.prevtxid,NSPV_ntzsproofresult.nexttxid) == 0 ) NSPV_ntzsproof_add(&NSPV_ntzsproofresult); fprintf(stderr,"got ntzproof response %u size.%d prev.%d next.%d\n",timestamp,(int32_t)response.size(),NSPV_ntzsproofresult.common.prevht,NSPV_ntzsproofresult.common.nextht); break; case NSPV_TXPROOFRESP: NSPV_txproof_purge(&NSPV_txproofresult); NSPV_rwtxproof(0,&response[1],&NSPV_txproofresult); if ( NSPV_txproof_find(NSPV_txproofresult.txid) == 0 ) NSPV_txproof_add(&NSPV_txproofresult); fprintf(stderr,"got txproof response %u size.%d %s ht.%d\n",timestamp,(int32_t)response.size(),NSPV_txproofresult.txid.GetHex().c_str(),NSPV_txproofresult.height); break; case NSPV_SPENTINFORESP: NSPV_spentinfo_purge(&NSPV_spentresult); NSPV_rwspentinfo(0,&response[1],&NSPV_spentresult); fprintf(stderr,"got spentinfo response %u size.%d\n",timestamp,(int32_t)response.size()); break; case NSPV_BROADCASTRESP: NSPV_broadcast_purge(&NSPV_broadcastresult); NSPV_rwbroadcastresp(0,&response[1],&NSPV_broadcastresult); fprintf(stderr,"got broadcast response %u size.%d %s retcode.%d\n",timestamp,(int32_t)response.size(),NSPV_broadcastresult.txid.GetHex().c_str(),NSPV_broadcastresult.retcode); break; case NSPV_CCMODULEUTXOSRESP: NSPV_utxosresp_purge(&NSPV_utxosresult); NSPV_rwutxosresp(0, &response[1], &NSPV_utxosresult); fprintf(stderr, "got cc module utxos response %u size.%d\n", timestamp, (int32_t)response.size()); break; default: fprintf(stderr,"unexpected response %02x size.%d at %u\n",response[0],(int32_t)response.size(),timestamp); break; } } } // superlite message issuing CNode *NSPV_req(CNode *pnode,uint8_t *msg,int32_t len,uint64_t mask,int32_t ind) { int32_t n,flag = 0; CNode *pnodes[64]; uint32_t timestamp = (uint32_t)time(NULL); if ( HUSH_NSPV_FULLNODE ) return(0); if ( pnode == 0 ) { memset(pnodes,0,sizeof(pnodes)); //LOCK(cs_vNodes); n = 0; BOOST_FOREACH(CNode *ptr,vNodes) { if ( ptr->prevtimes[ind] > timestamp ) ptr->prevtimes[ind] = 0; if ( ptr->hSocket == INVALID_SOCKET ) continue; if ( (ptr->nServices & mask) == mask && timestamp > ptr->prevtimes[ind] ) { flag = 1; pnodes[n++] = ptr; if ( n == sizeof(pnodes)/sizeof(*pnodes) ) break; } // else fprintf(stderr,"nServices %llx vs mask %llx, t%u vs %u, ind.%d\n",(long long)ptr->nServices,(long long)mask,timestamp,ptr->prevtimes[ind],ind); } if ( n > 0 ) pnode = pnodes[rand() % n]; } else flag = 1; if ( pnode != 0 ) { std::vector request; request.resize(len); memcpy(&request[0],msg,len); if ( (0) && HUSH_NSPV_SUPERLITE ) fprintf(stderr,"pushmessage [%d] len.%d\n",msg[0],len); pnode->PushMessage("getnSPV",request); pnode->prevtimes[ind] = timestamp; return(pnode); } else fprintf(stderr,"no pnodes\n"); return(0); } UniValue NSPV_logout() { UniValue result(UniValue::VOBJ); result.push_back(Pair("result","success")); if ( NSPV_logintime != 0 ) fprintf(stderr,"scrub wif and privkey from NSPV memory\n"); else result.push_back(Pair("status","wasnt logged in")); memset(NSPV_ntzsproofresp_cache,0,sizeof(NSPV_ntzsproofresp_cache)); memset(NSPV_txproof_cache,0,sizeof(NSPV_txproof_cache)); memset(NSPV_ntzsresp_cache,0,sizeof(NSPV_ntzsresp_cache)); memset(NSPV_wifstr,0,sizeof(NSPV_wifstr)); memset(&NSPV_key,0,sizeof(NSPV_key)); NSPV_logintime = 0; return(result); } // hush_nSPV from main polling loop (really this belongs in its own file, but it is so small, it ended up here) void hush_nSPV(CNode *pto) // polling loop from SendMessages { uint8_t msg[256]; int32_t i,len=0; uint32_t timestamp = (uint32_t)time(NULL); if ( NSPV_logintime != 0 && timestamp > NSPV_logintime+NSPV_AUTOLOGOUT ) NSPV_logout(); if ( (pto->nServices & NODE_NSPV) == 0 ) return; if ( pto->prevtimes[NSPV_INFO>>1] > timestamp ) pto->prevtimes[NSPV_INFO>>1] = 0; if ( HUSH_NSPV_SUPERLITE ) { if ( timestamp > NSPV_lastinfo + ASSETCHAINS_BLOCKTIME/2 && timestamp > pto->prevtimes[NSPV_INFO>>1] + 2*ASSETCHAINS_BLOCKTIME/3 ) { int32_t reqht; reqht = 0; len = 0; msg[len++] = NSPV_INFO; len += dragon_rwnum(1,&msg[len],sizeof(reqht),&reqht); //fprintf(stderr,"issue getinfo\n"); NSPV_req(pto,msg,len,NODE_NSPV,NSPV_INFO>>1); } } } UniValue NSPV_txproof_json(struct NSPV_txproof *ptr) { UniValue result(UniValue::VOBJ); result.push_back(Pair("txid",ptr->txid.GetHex())); result.push_back(Pair("height",(int64_t)ptr->height)); result.push_back(Pair("txlen",(int64_t)ptr->txlen)); result.push_back(Pair("txprooflen",(int64_t)ptr->txprooflen)); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_spentinfo_json(struct NSPV_spentinfo *ptr) { UniValue result(UniValue::VOBJ); result.push_back(Pair("result","success")); result.push_back(Pair("txid",ptr->txid.GetHex())); result.push_back(Pair("vout",(int64_t)ptr->vout)); result.push_back(Pair("spentheight",(int64_t)ptr->spent.height)); result.push_back(Pair("spenttxid",ptr->spent.txid.GetHex())); result.push_back(Pair("spentvini",(int64_t)ptr->spentvini)); result.push_back(Pair("spenttxlen",(int64_t)ptr->spent.txlen)); result.push_back(Pair("spenttxprooflen",(int64_t)ptr->spent.txprooflen)); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_ntz_json(struct NSPV_ntz *ptr) { UniValue result(UniValue::VOBJ); result.push_back(Pair("notarized_height",(int64_t)ptr->height)); result.push_back(Pair("notarized_blockhash",ptr->blockhash.GetHex())); result.push_back(Pair("notarization_txid",ptr->txid.GetHex())); result.push_back(Pair("notarization_txidheight",(int64_t)ptr->txidheight)); result.push_back(Pair("notarization_desttxid",ptr->othertxid.GetHex())); return(result); } UniValue NSPV_header_json(struct NSPV_equihdr *hdr,int32_t height) { UniValue item(UniValue::VOBJ); item.push_back(Pair("height",(int64_t)height)); item.push_back(Pair("blockhash",NSPV_hdrhash(hdr).GetHex())); item.push_back(Pair("hashPrevBlock",hdr->hashPrevBlock.GetHex())); item.push_back(Pair("hashMerkleRoot",hdr->hashMerkleRoot.GetHex())); item.push_back(Pair("nTime",(int64_t)hdr->nTime)); item.push_back(Pair("nBits",(int64_t)hdr->nBits)); return(item); } UniValue NSPV_headers_json(struct NSPV_equihdr *hdrs,int32_t numhdrs,int32_t height) { UniValue array(UniValue::VARR); int32_t i; for (i=0; iheight)); result.push_back(Pair("chaintip",ptr->blockhash.GetHex())); result.push_back(Pair("notarization",NSPV_ntz_json(&ptr->notarization))); result.push_back(Pair("header",NSPV_header_json(&ptr->H,ptr->hdrheight))); result.push_back(Pair("protocolversion",(int64_t)ptr->version)); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_utxoresp_json(struct NSPV_utxoresp *utxos,int32_t numutxos) { UniValue array(UniValue::VARR); int32_t i; for (i=0; iutxos,ptr->numutxos))); result.push_back(Pair("address",ptr->coinaddr)); result.push_back(Pair("isCC",ptr->CCflag)); result.push_back(Pair("height",(int64_t)ptr->nodeheight)); result.push_back(Pair("numutxos",(int64_t)ptr->numutxos)); result.push_back(Pair("balance",(double)ptr->total/COIN)); result.push_back(Pair("filter",(int64_t)ptr->filter)); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_txidresp_json(struct NSPV_txidresp *utxos,int32_t numutxos) { UniValue array(UniValue::VARR); int32_t i; for (i=0; i 0 ) item.push_back(Pair("vout",(int64_t)utxos[i].vout)); else item.push_back(Pair("vin",(int64_t)utxos[i].vout)); array.push_back(item); } return(array); } UniValue NSPV_txidsresp_json(struct NSPV_txidsresp *ptr) { UniValue result(UniValue::VOBJ); result.push_back(Pair("result","success")); result.push_back(Pair("txids",NSPV_txidresp_json(ptr->txids,ptr->numtxids))); result.push_back(Pair("address",ptr->coinaddr)); result.push_back(Pair("isCC",ptr->CCflag)); result.push_back(Pair("height",(int64_t)ptr->nodeheight)); result.push_back(Pair("numtxids",(int64_t)ptr->numtxids)); result.push_back(Pair("filter",(int64_t)ptr->filter)); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_mempoolresp_json(struct NSPV_mempoolresp *ptr) { UniValue result(UniValue::VOBJ),array(UniValue::VARR); int32_t i; result.push_back(Pair("result","success")); for (i=0; inumtxids; i++) array.push_back(ptr->txids[i].GetHex().c_str()); result.push_back(Pair("txids",array)); result.push_back(Pair("address",ptr->coinaddr)); result.push_back(Pair("isCC",ptr->CCflag)); result.push_back(Pair("height",(int64_t)ptr->nodeheight)); result.push_back(Pair("numtxids",(int64_t)ptr->numtxids)); result.push_back(Pair("txid",ptr->txid.GetHex().c_str())); result.push_back(Pair("vout",(int64_t)ptr->vout)); result.push_back(Pair("funcid",(int64_t)ptr->funcid)); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_ntzsresp_json(struct NSPV_ntzsresp *ptr) { UniValue result(UniValue::VOBJ); result.push_back(Pair("result","success")); result.push_back(Pair("prev",NSPV_ntz_json(&ptr->prevntz))); result.push_back(Pair("next",NSPV_ntz_json(&ptr->nextntz))); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_ntzsproof_json(struct NSPV_ntzsproofresp *ptr) { UniValue result(UniValue::VOBJ); result.push_back(Pair("result","success")); result.push_back(Pair("prevht",(int64_t)ptr->common.prevht)); result.push_back(Pair("nextht",(int64_t)ptr->common.nextht)); result.push_back(Pair("prevtxid",ptr->prevtxid.GetHex())); result.push_back(Pair("prevtxidht",(int64_t)ptr->prevtxidht)); result.push_back(Pair("prevtxlen",(int64_t)ptr->prevtxlen)); result.push_back(Pair("nexttxid",ptr->nexttxid.GetHex())); result.push_back(Pair("nexttxidht",(int64_t)ptr->nexttxidht)); result.push_back(Pair("nexttxlen",(int64_t)ptr->nexttxlen)); result.push_back(Pair("numhdrs",(int64_t)ptr->common.numhdrs)); result.push_back(Pair("headers",NSPV_headers_json(ptr->common.hdrs,ptr->common.numhdrs,ptr->common.prevht))); result.push_back(Pair("lastpeer",NSPV_lastpeer)); //fprintf(stderr,"ntzs_proof %s %d, %s %d\n",ptr->prevtxid.GetHex().c_str(),ptr->common.prevht,ptr->nexttxid.GetHex().c_str(),ptr->common.nextht); return(result); } UniValue NSPV_broadcast_json(struct NSPV_broadcastresp *ptr,uint256 txid) { UniValue result(UniValue::VOBJ); result.push_back(Pair("result","success")); result.push_back(Pair("expected",txid.GetHex())); result.push_back(Pair("broadcast",ptr->txid.GetHex())); result.push_back(Pair("retcode",(int64_t)ptr->retcode)); switch ( ptr->retcode ) { case 1: result.push_back(Pair("type","broadcast and mempool")); break; case 0: result.push_back(Pair("type","broadcast")); break; case -1: result.push_back(Pair("type","decode error")); break; case -2: result.push_back(Pair("type","timeout")); break; case -3: result.push_back(Pair("type","error adding to mempool")); break; default: result.push_back(Pair("type","unknown")); break; } result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_login(char *wifstr) { UniValue result(UniValue::VOBJ); char coinaddr[64]; uint8_t data[128]; int32_t len,valid = 0; NSPV_logout(); len = bitcoin_base58decode(data,wifstr); if ( strlen(wifstr) < 64 && (len == 38 && data[len-5] == 1) || (len == 37 && data[len-5] != 1) ) valid = 1; if ( valid == 0 || data[0] != 188 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","invalid wif")); result.push_back(Pair("len",(int64_t)len)); result.push_back(Pair("prefix",(int64_t)data[0])); return(result); } memset(NSPV_wifstr,0,sizeof(NSPV_wifstr)); NSPV_logintime = (uint32_t)time(NULL); if ( strcmp(NSPV_wifstr,wifstr) != 0 ) { strncpy(NSPV_wifstr,wifstr,sizeof(NSPV_wifstr)-1); NSPV_key = DecodeSecret(wifstr); } result.push_back(Pair("result","success")); result.push_back(Pair("status","wif will expire in 777 seconds")); CPubKey pubkey = NSPV_key.GetPubKey(); CKeyID vchAddress = pubkey.GetID(); NSPV_address = EncodeDestination(vchAddress); result.push_back(Pair("address",NSPV_address)); result.push_back(Pair("pubkey",HexStr(pubkey))); strcpy(NSPV_pubkeystr,HexStr(pubkey).c_str()); if ( HUSH_NSPV_SUPERLITE ) decode_hex(NOTARY_PUBKEY33,33,NSPV_pubkeystr); result.push_back(Pair("wifprefix",(int64_t)data[0])); result.push_back(Pair("compressed",(int64_t)(data[len-5] == 1))); memset(data,0,sizeof(data)); return(result); } UniValue NSPV_getinfo_req(int32_t reqht) { uint8_t msg[512]; int32_t i,iter,len = 0; struct NSPV_inforesp I; NSPV_inforesp_purge(&NSPV_inforesult); msg[len++] = NSPV_INFO; len += dragon_rwnum(1,&msg[len],sizeof(reqht),&reqht); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 ) { for (i=0; i 0 ) { NSPV_getinfo_req(hdrheight); if ( NSPV_inforesult.hdrheight == hdrheight ) { timestamp = NSPV_inforesult.H.nTime; NSPV_inforesult = old; fprintf(stderr,"NSPV_blocktime ht.%d -> t%u\n",hdrheight,timestamp); return(timestamp); } } NSPV_inforesult = old; return(0); } UniValue NSPV_addressutxos(char *coinaddr,int32_t CCflag,int32_t skipcount,int32_t filter) { UniValue result(UniValue::VOBJ); uint8_t msg[512]; int32_t i,iter,slen,len = 0; //fprintf(stderr,"utxos %s NSPV addr %s\n",coinaddr,NSPV_address.c_str()); //if ( NSPV_utxosresult.nodeheight >= NSPV_inforesult.height && strcmp(coinaddr,NSPV_utxosresult.coinaddr) == 0 && CCflag == NSPV_utxosresult.CCflag && skipcount == NSPV_utxosresult.skipcount && filter == NSPV_utxosresult.filter ) // return(NSPV_utxosresp_json(&NSPV_utxosresult)); if ( skipcount < 0 ) skipcount = 0; NSPV_utxosresp_purge(&NSPV_utxosresult); if ( bitcoin_base58decode(msg,coinaddr) != 25 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","invalid address")); return(result); } slen = (int32_t)strlen(coinaddr); msg[len++] = NSPV_UTXOS; msg[len++] = slen; memcpy(&msg[len],coinaddr,slen), len += slen; msg[len++] = (CCflag != 0); len += dragon_rwnum(1,&msg[len],sizeof(skipcount),&skipcount); len += dragon_rwnum(1,&msg[len],sizeof(filter),&filter); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_ADDRINDEX,msg[0]>>1) != 0 ) { for (i=0; i= NSPV_inforesult.height) && strcmp(coinaddr,NSPV_utxosresult.coinaddr) == 0 && CCflag == NSPV_utxosresult.CCflag ) return(NSPV_utxosresp_json(&NSPV_utxosresult)); } } else sleep(1); result.push_back(Pair("result","error")); result.push_back(Pair("error","no utxos result")); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_addresstxids(char *coinaddr,int32_t CCflag,int32_t skipcount,int32_t filter) { UniValue result(UniValue::VOBJ); uint8_t msg[512]; int32_t i,iter,slen,len = 0; if ( NSPV_txidsresult.nodeheight >= NSPV_inforesult.height && strcmp(coinaddr,NSPV_txidsresult.coinaddr) == 0 && CCflag == NSPV_txidsresult.CCflag && skipcount == NSPV_txidsresult.skipcount ) return(NSPV_txidsresp_json(&NSPV_txidsresult)); if ( skipcount < 0 ) skipcount = 0; NSPV_txidsresp_purge(&NSPV_txidsresult); if ( bitcoin_base58decode(msg,coinaddr) != 25 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","invalid address")); return(result); } slen = (int32_t)strlen(coinaddr); msg[len++] = NSPV_TXIDS; msg[len++] = slen; memcpy(&msg[len],coinaddr,slen), len += slen; msg[len++] = (CCflag != 0); len += dragon_rwnum(1,&msg[len],sizeof(skipcount),&skipcount); len += dragon_rwnum(1,&msg[len],sizeof(filter),&filter); //fprintf(stderr,"skipcount.%d\n",skipcount); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_ADDRINDEX,msg[0]>>1) != 0 ) { for (i=0; i= NSPV_inforesult.height) && strcmp(coinaddr,NSPV_txidsresult.coinaddr) == 0 && CCflag == NSPV_txidsresult.CCflag ) return(NSPV_txidsresp_json(&NSPV_txidsresult)); } } else sleep(1); result.push_back(Pair("result","error")); result.push_back(Pair("error","no txid result")); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_ccaddresstxids(char *coinaddr,int32_t CCflag,int32_t skipcount,uint256 filtertxid,uint8_t evalcode, uint8_t func) { UniValue result(UniValue::VOBJ); uint8_t msg[512],funcid=NSPV_CC_TXIDS; char zeroes[64]; int32_t i,iter,slen,len = 0,vout; NSPV_mempoolresp_purge(&NSPV_mempoolresult); memset(zeroes,0,sizeof(zeroes)); if ( coinaddr == 0 ) coinaddr = zeroes; if ( coinaddr[0] != 0 && bitcoin_base58decode(msg,coinaddr) != 25 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","invalid address")); return(result); } vout=skipcount << 16 | evalcode << 8 | func; msg[len++] = NSPV_MEMPOOL; msg[len++] = (CCflag != 0); len += dragon_rwnum(1,&msg[len],sizeof(funcid),&funcid); len += dragon_rwnum(1,&msg[len],sizeof(vout),&vout); len += dragon_rwbignum(1,&msg[len],sizeof(filtertxid),(uint8_t *)&filtertxid); slen = (int32_t)strlen(coinaddr); msg[len++] = slen; memcpy(&msg[len],coinaddr,slen), len += slen; fprintf(stderr,"(%s) func.%d CC.%d %s skipcount.%d len.%d\n",coinaddr,NSPV_CC_TXIDS,CCflag,filtertxid.GetHex().c_str(),skipcount,len); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 ) { for (i=0; i= NSPV_inforesult.height && strcmp(coinaddr,NSPV_mempoolresult.coinaddr) == 0 && CCflag == NSPV_mempoolresult.CCflag && filtertxid == NSPV_mempoolresult.txid && vout == NSPV_mempoolresult.vout && funcid == NSPV_mempoolresult.funcid ) return(NSPV_mempoolresp_json(&NSPV_mempoolresult)); } } else sleep(1); result.push_back(Pair("result","error")); result.push_back(Pair("error","no txid result")); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } UniValue NSPV_mempooltxids(char *coinaddr,int32_t CCflag,uint8_t funcid,uint256 txid,int32_t vout) { UniValue result(UniValue::VOBJ); uint8_t msg[512]; char zeroes[64]; int32_t i,iter,slen,len = 0; NSPV_mempoolresp_purge(&NSPV_mempoolresult); memset(zeroes,0,sizeof(zeroes)); if ( coinaddr == 0 ) coinaddr = zeroes; if ( coinaddr[0] != 0 && bitcoin_base58decode(msg,coinaddr) != 25 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","invalid address")); return(result); } msg[len++] = NSPV_MEMPOOL; msg[len++] = (CCflag != 0); len += dragon_rwnum(1,&msg[len],sizeof(funcid),&funcid); len += dragon_rwnum(1,&msg[len],sizeof(vout),&vout); len += dragon_rwbignum(1,&msg[len],sizeof(txid),(uint8_t *)&txid); slen = (int32_t)strlen(coinaddr); msg[len++] = slen; memcpy(&msg[len],coinaddr,slen), len += slen; fprintf(stderr,"(%s) func.%d CC.%d %s/v%d len.%d\n",coinaddr,funcid,CCflag,txid.GetHex().c_str(),vout,len); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 ) { for (i=0; i= NSPV_inforesult.height && strcmp(coinaddr,NSPV_mempoolresult.coinaddr) == 0 && CCflag == NSPV_mempoolresult.CCflag && txid == NSPV_mempoolresult.txid && vout == NSPV_mempoolresult.vout && funcid == NSPV_mempoolresult.funcid ) return(NSPV_mempoolresp_json(&NSPV_mempoolresult)); } } else sleep(1); result.push_back(Pair("result","error")); result.push_back(Pair("error","no txid result")); result.push_back(Pair("lastpeer",NSPV_lastpeer)); return(result); } int32_t NSPV_coinaddr_inmempool(char const *logcategory,char *coinaddr,uint8_t CCflag) { NSPV_mempooltxids(coinaddr,CCflag,NSPV_MEMPOOL_ADDRESS,zeroid,-1); if ( NSPV_mempoolresult.txids != 0 && NSPV_mempoolresult.numtxids >= 1 && strcmp(NSPV_mempoolresult.coinaddr,coinaddr) == 0 && NSPV_mempoolresult.CCflag == CCflag ) { LogPrint(logcategory,"found (%s) vout in mempool\n",coinaddr); return(true); } else return(false); } bool NSPV_spentinmempool(uint256 &spenttxid,int32_t &spentvini,uint256 txid,int32_t vout) { NSPV_mempooltxids((char *)"",0,NSPV_MEMPOOL_ISSPENT,txid,vout); if ( NSPV_mempoolresult.txids != 0 && NSPV_mempoolresult.numtxids == 1 && NSPV_mempoolresult.txid == txid ) { spenttxid = NSPV_mempoolresult.txids[0]; spentvini = NSPV_mempoolresult.vindex; return(true); } else return(false); } bool NSPV_inmempool(uint256 txid) { NSPV_mempooltxids((char *)"",0,NSPV_MEMPOOL_INMEMPOOL,txid,0); if ( NSPV_mempoolresult.txids != 0 && NSPV_mempoolresult.numtxids == 1 && NSPV_mempoolresult.txids[0] == txid ) return(true); else return(false); } bool NSPV_evalcode_inmempool(uint8_t evalcode,uint8_t funcid) { int32_t vout; vout = ((uint32_t)funcid << 8) | evalcode; NSPV_mempooltxids((char *)"",1,NSPV_MEMPOOL_CCEVALCODE,zeroid,vout); if ( NSPV_mempoolresult.txids != 0 && NSPV_mempoolresult.numtxids >= 1 && NSPV_mempoolresult.vout == vout ) return(true); else return(false); } UniValue NSPV_notarizations(int32_t reqheight) { uint8_t msg[512]; int32_t i,iter,len = 0; struct NSPV_ntzsresp N,*ptr; if ( (ptr= NSPV_ntzsresp_find(reqheight)) != 0 ) { fprintf(stderr,"FROM CACHE NSPV_notarizations.%d\n",reqheight); NSPV_ntzsresp_purge(&NSPV_ntzsresult); NSPV_ntzsresp_copy(&NSPV_ntzsresult,ptr); return(NSPV_ntzsresp_json(ptr)); } msg[len++] = NSPV_NTZS; len += dragon_rwnum(1,&msg[len],sizeof(reqheight),&reqheight); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 ) { for (i=0; iprevtxid.GetHex().c_str(),ptr->nexttxid.GetHex().c_str()); NSPV_ntzsproofresp_purge(&NSPV_ntzsproofresult); NSPV_ntzsproofresp_copy(&NSPV_ntzsproofresult,ptr); return(NSPV_ntzsproof_json(ptr)); } NSPV_ntzsproofresp_purge(&NSPV_ntzsproofresult); msg[len++] = NSPV_NTZSPROOF; len += dragon_rwbignum(1,&msg[len],sizeof(prevtxid),(uint8_t *)&prevtxid); len += dragon_rwbignum(1,&msg[len],sizeof(nexttxid),(uint8_t *)&nexttxid); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 ) { for (i=0; i>1) != 0 ) { for (i=0; i>1) != 0 ) { for (i=0; i> 1; data = (uint8_t *)malloc(n); decode_hex(data,n,hex); txid = NSPV_doublesha256(data,n); msg = (uint8_t *)malloc(1 + sizeof(txid) + sizeof(n) + n); msg[len++] = NSPV_BROADCAST; len += dragon_rwbignum(1,&msg[len],sizeof(txid),(uint8_t *)&txid); len += dragon_rwnum(1,&msg[len],sizeof(n),&n); memcpy(&msg[len],data,n), len += n; free(data); //fprintf(stderr,"send txid.%s\n",txid.GetHex().c_str()); for (iter=0; iter<3; iter++) if ( NSPV_req(0,msg,len,NODE_NSPV,msg[0]>>1) != 0 ) { for (i=0; i> 1) != 0) { for (i = 0; i= NSPV_inforesult.height) && strcmp(coinaddr, NSPV_utxosresult.coinaddr) == 0 && CCflag == NSPV_utxosresult.CCflag) return(NSPV_utxosresp_json(&NSPV_utxosresult)); } } else sleep(1); result.push_back(Pair("result", "error")); result.push_back(Pair("error", "no utxos result")); result.push_back(Pair("lastpeer", NSPV_lastpeer)); return(result); } #endif // HUSH_NSPVSUPERLITE_H