// Copyright (c) 2016-2024 The Hush developers // Distributed under the GPLv3 software license, see the accompanying // file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html /****************************************************************************** * 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. * * * ******************************************************************************/ // todo: // spentinfo via CC // headers "sync" make sure it connects to prior blocks to notarization. use getinfo hdrht to get missing hdrs // make sure to sanity check all vector lengths on receipt // make sure no files are updated (this is to allow nSPV=1 and later nSPV=0 without affecting database) // bug: under load, fullnode was returning all 0 nServices #ifndef HUSH_NSPV_H #define HUSH_NSPV_H int32_t dragon_rwbuf(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *buf) { if ( rwflag != 0 ) memcpy(serialized,buf,len); else memcpy(buf,serialized,len); return(len); } int32_t NSPV_rwequihdr(int32_t rwflag,uint8_t *serialized,struct NSPV_equihdr *ptr) { int32_t len = 0; len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nVersion),&ptr->nVersion); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->hashPrevBlock),(uint8_t *)&ptr->hashPrevBlock); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->hashMerkleRoot),(uint8_t *)&ptr->hashMerkleRoot); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->hashFinalSaplingRoot),(uint8_t *)&ptr->hashFinalSaplingRoot); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nTime),&ptr->nTime); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nBits),&ptr->nBits); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->nNonce),(uint8_t *)&ptr->nNonce); len += dragon_rwbuf(rwflag,&serialized[len],sizeof(ptr->nSolution),ptr->nSolution); return(len); } int32_t dragon_rwequihdrvec(int32_t rwflag,uint8_t *serialized,uint16_t *vecsizep,struct NSPV_equihdr **ptrp) { int32_t i,vsize,len = 0; len += dragon_rwnum(rwflag,&serialized[len],sizeof(*vecsizep),vecsizep); if ( (vsize= *vecsizep) != 0 ) { //fprintf(stderr,"vsize.%d ptrp.%p alloc %ld\n",vsize,*ptrp,sizeof(struct NSPV_equihdr)*vsize); if ( *ptrp == 0 ) *ptrp = (struct NSPV_equihdr *)calloc(sizeof(struct NSPV_equihdr),vsize); // relies on uint16_t being "small" to prevent mem exhaustion for (i=0; i 0 && vsize < MAX_TX_SIZE_AFTER_SAPLING ) { if ( *ptrp == 0 ) *ptrp = (uint8_t *)calloc(1,vsize); len += dragon_rwbuf(rwflag,&serialized[len],vsize,*ptrp); } return(len); } int32_t NSPV_rwutxoresp(int32_t rwflag,uint8_t *serialized,struct NSPV_utxoresp *ptr) { int32_t len = 0; len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txid),(uint8_t *)&ptr->txid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->satoshis),&ptr->satoshis); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->extradata),&ptr->extradata); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->vout),&ptr->vout); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->height),&ptr->height); return(len); } int32_t NSPV_rwutxosresp(int32_t rwflag,uint8_t *serialized,struct NSPV_utxosresp *ptr) // check mempool { int32_t i,len = 0; len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->numutxos),&ptr->numutxos); if ( ptr->numutxos != 0 ) { if ( ptr->utxos == 0 ) ptr->utxos = (struct NSPV_utxoresp *)calloc(sizeof(*ptr->utxos),ptr->numutxos); // relies on uint16_t being "small" to prevent mem exhaustion for (i=0; inumutxos; i++) len += NSPV_rwutxoresp(rwflag,&serialized[len],&ptr->utxos[i]); } len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->total),&ptr->total); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->interest),&ptr->interest); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nodeheight),&ptr->nodeheight); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->filter),&ptr->filter); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->CCflag),&ptr->CCflag); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->skipcount),&ptr->skipcount); if ( rwflag != 0 ) { memcpy(&serialized[len],ptr->coinaddr,sizeof(ptr->coinaddr)); len += sizeof(ptr->coinaddr); } else { memcpy(ptr->coinaddr,&serialized[len],sizeof(ptr->coinaddr)); len += sizeof(ptr->coinaddr); } return(len); } void NSPV_utxosresp_purge(struct NSPV_utxosresp *ptr) { if ( ptr != 0 ) { if ( ptr->utxos != 0 ) free(ptr->utxos); memset(ptr,0,sizeof(*ptr)); } } void NSPV_utxosresp_copy(struct NSPV_utxosresp *dest,struct NSPV_utxosresp *ptr) { *dest = *ptr; if ( ptr->utxos != 0 ) { dest->utxos = (struct NSPV_utxoresp *)malloc(ptr->numutxos * sizeof(*ptr->utxos)); memcpy(dest->utxos,ptr->utxos,ptr->numutxos * sizeof(*ptr->utxos)); } } int32_t NSPV_rwtxidresp(int32_t rwflag,uint8_t *serialized,struct NSPV_txidresp *ptr) { int32_t len = 0; len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txid),(uint8_t *)&ptr->txid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->satoshis),&ptr->satoshis); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->vout),&ptr->vout); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->height),&ptr->height); return(len); } int32_t NSPV_rwtxidsresp(int32_t rwflag,uint8_t *serialized,struct NSPV_txidsresp *ptr) { int32_t i,len = 0; len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->numtxids),&ptr->numtxids); if ( ptr->numtxids != 0 ) { if ( ptr->txids == 0 ) ptr->txids = (struct NSPV_txidresp *)calloc(sizeof(*ptr->txids),ptr->numtxids); for (i=0; inumtxids; i++) len += NSPV_rwtxidresp(rwflag,&serialized[len],&ptr->txids[i]); } len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nodeheight),&ptr->nodeheight); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->filter),&ptr->filter); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->CCflag),&ptr->CCflag); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->skipcount),&ptr->skipcount); if ( rwflag != 0 ) { memcpy(&serialized[len],ptr->coinaddr,sizeof(ptr->coinaddr)); len += sizeof(ptr->coinaddr); } else { memcpy(ptr->coinaddr,&serialized[len],sizeof(ptr->coinaddr)); len += sizeof(ptr->coinaddr); } //fprintf(stderr,"rwlen.%d\n",len); return(len); } void NSPV_txidsresp_purge(struct NSPV_txidsresp *ptr) { if ( ptr != 0 ) { if ( ptr->txids != 0 ) free(ptr->txids); memset(ptr,0,sizeof(*ptr)); } } void NSPV_txidsresp_copy(struct NSPV_txidsresp *dest,struct NSPV_txidsresp *ptr) { *dest = *ptr; if ( ptr->txids != 0 ) { dest->txids = (struct NSPV_txidresp *)malloc(ptr->numtxids * sizeof(*ptr->txids)); memcpy(dest->txids,ptr->txids,ptr->numtxids * sizeof(*ptr->txids)); } } int32_t NSPV_rwmempoolresp(int32_t rwflag,uint8_t *serialized,struct NSPV_mempoolresp *ptr) { int32_t i,len = 0; len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->numtxids),&ptr->numtxids); if ( ptr->numtxids != 0 ) { if ( ptr->txids == 0 ) ptr->txids = (uint256 *)calloc(sizeof(*ptr->txids),ptr->numtxids); for (i=0; inumtxids; i++) len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txids[i]),(uint8_t *)&ptr->txids[i]); } len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txid),(uint8_t *)&ptr->txid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nodeheight),&ptr->nodeheight); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->vout),&ptr->vout); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->vindex),&ptr->vindex); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->CCflag),&ptr->CCflag); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->funcid),&ptr->funcid); if ( rwflag != 0 ) { memcpy(&serialized[len],ptr->coinaddr,sizeof(ptr->coinaddr)); len += sizeof(ptr->coinaddr); } else { memcpy(ptr->coinaddr,&serialized[len],sizeof(ptr->coinaddr)); len += sizeof(ptr->coinaddr); } //fprintf(stderr,"NSPV_rwmempoolresp rwlen.%d\n",len); return(len); } void NSPV_mempoolresp_purge(struct NSPV_mempoolresp *ptr) { if ( ptr != 0 ) { if ( ptr->txids != 0 ) free(ptr->txids); memset(ptr,0,sizeof(*ptr)); } } void NSPV_mempoolresp_copy(struct NSPV_mempoolresp *dest,struct NSPV_mempoolresp *ptr) { *dest = *ptr; if ( ptr->txids != 0 ) { dest->txids = (uint256 *)malloc(ptr->numtxids * sizeof(*ptr->txids)); memcpy(dest->txids,ptr->txids,ptr->numtxids * sizeof(*ptr->txids)); } } int32_t NSPV_rwntz(int32_t rwflag,uint8_t *serialized,struct NSPV_ntz *ptr) { int32_t len = 0; len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->blockhash),(uint8_t *)&ptr->blockhash); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txid),(uint8_t *)&ptr->txid); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->othertxid),(uint8_t *)&ptr->othertxid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->height),&ptr->height); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->txidheight),&ptr->txidheight); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->timestamp),&ptr->timestamp); return(len); } int32_t NSPV_rwntzsresp(int32_t rwflag,uint8_t *serialized,struct NSPV_ntzsresp *ptr) { int32_t len = 0; len += NSPV_rwntz(rwflag,&serialized[len],&ptr->prevntz); len += NSPV_rwntz(rwflag,&serialized[len],&ptr->nextntz); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->reqheight),&ptr->reqheight); return(len); } void NSPV_ntzsresp_copy(struct NSPV_ntzsresp *dest,struct NSPV_ntzsresp *ptr) { *dest = *ptr; } void NSPV_ntzsresp_purge(struct NSPV_ntzsresp *ptr) { if ( ptr != 0 ) memset(ptr,0,sizeof(*ptr)); } int32_t NSPV_rwinforesp(int32_t rwflag,uint8_t *serialized,struct NSPV_inforesp *ptr) { int32_t len = 0; len += NSPV_rwntz(rwflag,&serialized[len],&ptr->notarization); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->blockhash),(uint8_t *)&ptr->blockhash); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->height),&ptr->height); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->hdrheight),&ptr->hdrheight); len += NSPV_rwequihdr(rwflag,&serialized[len],&ptr->H); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->version),&ptr->version); //fprintf(stderr,"getinfo rwlen.%d\n",len); return(len); } void NSPV_inforesp_purge(struct NSPV_inforesp *ptr) { if ( ptr != 0 ) memset(ptr,0,sizeof(*ptr)); } int32_t NSPV_rwtxproof(int32_t rwflag,uint8_t *serialized,struct NSPV_txproof *ptr) { int32_t len = 0; len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txid),(uint8_t *)&ptr->txid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->unspentvalue),&ptr->unspentvalue); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->height),&ptr->height); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->vout),&ptr->vout); len += dragon_rwuint8vec(rwflag,&serialized[len],&ptr->txlen,&ptr->tx); len += dragon_rwuint8vec(rwflag,&serialized[len],&ptr->txprooflen,&ptr->txproof); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->hashblock),(uint8_t *)&ptr->hashblock); return(len); } void NSPV_txproof_copy(struct NSPV_txproof *dest,struct NSPV_txproof *ptr) { *dest = *ptr; if ( ptr->tx != 0 && ptr->txlen < MAX_TX_SIZE_AFTER_SAPLING ) { dest->tx = (uint8_t *)malloc(ptr->txlen); memcpy(dest->tx,ptr->tx,ptr->txlen); } if ( ptr->txproof != 0 ) { dest->txproof = (uint8_t *)malloc(ptr->txprooflen); memcpy(dest->txproof,ptr->txproof,ptr->txprooflen); } } void NSPV_txproof_purge(struct NSPV_txproof *ptr) { if ( ptr != 0 ) { if ( ptr->tx != 0 ) free(ptr->tx); if ( ptr->txproof != 0 ) free(ptr->txproof); memset(ptr,0,sizeof(*ptr)); } } int32_t NSPV_rwntzproofshared(int32_t rwflag,uint8_t *serialized,struct NSPV_ntzproofshared *ptr) { int32_t len = 0; len += dragon_rwequihdrvec(rwflag,&serialized[len],&ptr->numhdrs,&ptr->hdrs); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->prevht),&ptr->prevht); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nextht),&ptr->nextht); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->pad32),&ptr->pad32); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->pad16),&ptr->pad16); //fprintf(stderr,"rwcommon prev.%d next.%d\n",ptr->prevht,ptr->nextht); return(len); } int32_t NSPV_rwntzsproofresp(int32_t rwflag,uint8_t *serialized,struct NSPV_ntzsproofresp *ptr) { int32_t len = 0; len += NSPV_rwntzproofshared(rwflag,&serialized[len],&ptr->common); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->prevtxid),(uint8_t *)&ptr->prevtxid); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->nexttxid),(uint8_t *)&ptr->nexttxid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->prevtxidht),&ptr->prevtxidht); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->nexttxidht),&ptr->nexttxidht); len += dragon_rwuint8vec(rwflag,&serialized[len],&ptr->prevtxlen,&ptr->prevntz); len += dragon_rwuint8vec(rwflag,&serialized[len],&ptr->nexttxlen,&ptr->nextntz); //fprintf(stderr,"retlen.%d\n",len); return(len); } void NSPV_ntzsproofresp_copy(struct NSPV_ntzsproofresp *dest,struct NSPV_ntzsproofresp *ptr) { *dest = *ptr; if ( ptr->common.hdrs != 0 ) { dest->common.hdrs = (struct NSPV_equihdr *)malloc(ptr->common.numhdrs * sizeof(*ptr->common.hdrs)); memcpy(dest->common.hdrs,ptr->common.hdrs,ptr->common.numhdrs * sizeof(*ptr->common.hdrs)); } if ( ptr->prevntz != 0 ) { dest->prevntz = (uint8_t *)malloc(ptr->prevtxlen); memcpy(dest->prevntz,ptr->prevntz,ptr->prevtxlen); } if ( ptr->nextntz != 0 ) { dest->nextntz = (uint8_t *)malloc(ptr->nexttxlen); memcpy(dest->nextntz,ptr->nextntz,ptr->nexttxlen); } } void NSPV_ntzsproofresp_purge(struct NSPV_ntzsproofresp *ptr) { if ( ptr != 0 ) { if ( ptr->common.hdrs != 0 ) free(ptr->common.hdrs); if ( ptr->prevntz != 0 ) free(ptr->prevntz); if ( ptr->nextntz != 0 ) free(ptr->nextntz); memset(ptr,0,sizeof(*ptr)); } } int32_t NSPV_rwspentinfo(int32_t rwflag,uint8_t *serialized,struct NSPV_spentinfo *ptr) // check mempool { int32_t len = 0; len += NSPV_rwtxproof(rwflag,&serialized[len],&ptr->spent); len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txid),(uint8_t *)&ptr->txid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->vout),&ptr->vout); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->spentvini),&ptr->spentvini); return(len); } void NSPV_spentinfo_purge(struct NSPV_spentinfo *ptr) { if ( ptr != 0 ) { NSPV_txproof_purge(&ptr->spent); memset(ptr,0,sizeof(*ptr)); } } int32_t NSPV_rwbroadcastresp(int32_t rwflag,uint8_t *serialized,struct NSPV_broadcastresp *ptr) { int32_t len = 0; len += dragon_rwbignum(rwflag,&serialized[len],sizeof(ptr->txid),(uint8_t *)&ptr->txid); len += dragon_rwnum(rwflag,&serialized[len],sizeof(ptr->retcode),&ptr->retcode); return(len); } void NSPV_broadcast_purge(struct NSPV_broadcastresp *ptr) { if ( ptr != 0 ) 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+=dragon_rwbuf(rwflag,&serialized[len],sizeof(ptr->method),(uint8_t*)ptr->method); len+=dragon_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)); } // useful utility functions uint256 NSPV_doublesha256(uint8_t *data,int32_t datalen) { bits256 _hash; uint256 hash; int32_t i; _hash = bits256_doublesha256(0,data,datalen); for (i=0; i<32; i++) ((uint8_t *)&hash)[i] = _hash.bytes[31 - i]; return(hash); } uint256 NSPV_hdrhash(struct NSPV_equihdr *hdr) { CBlockHeader block; block.nVersion = hdr->nVersion; block.hashPrevBlock = hdr->hashPrevBlock; block.hashMerkleRoot = hdr->hashMerkleRoot; block.hashFinalSaplingRoot = hdr->hashFinalSaplingRoot; block.nTime = hdr->nTime; block.nBits = hdr->nBits; block.nNonce = hdr->nNonce; block.nSolution.resize(sizeof(hdr->nSolution)); memcpy(&block.nSolution[0],hdr->nSolution,sizeof(hdr->nSolution)); return(block.GetHash()); } int32_t NSPV_txextract(CTransaction &tx,uint8_t *data,int32_t datalen) { std::vector rawdata; if ( datalen < MAX_TX_SIZE_AFTER_SAPLING ) { rawdata.resize(datalen); memcpy(&rawdata[0],data,datalen); if ( DecodeHexTx(tx,HexStr(rawdata)) != 0 ) return(0); } return(-1); } bool NSPV_SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey,uint32_t nTime); int32_t NSPV_fastnotariescount(CTransaction tx,uint8_t elected[64][33],uint32_t nTime) { CPubKey pubkeys[64]; uint8_t sig[512]; CScript scriptPubKeys[64]; CMutableTransaction mtx(tx); int32_t vini,j,siglen,retval; uint64_t mask = 0; char *str; std::vector> vData; for (j=0; j<64; j++) { pubkeys[j] = buf2pk(elected[j]); scriptPubKeys[j] = (CScript() << ParseHex(HexStr(pubkeys[j])) << OP_CHECKSIG); //fprintf(stderr,"%d %s\n",j,HexStr(pubkeys[j]).c_str()); } fprintf(stderr,"txid %s\n",tx.GetHash().GetHex().c_str()); //for (vini=0; vini opret,uint256 txid) { uint256 desttxid; int32_t i; dragon_rwnum(0,&opret[32],sizeof(*heightp),heightp); for (i=0; i<32; i++) ((uint8_t *)blockhashp)[i] = opret[i]; for (i=0; i<32; i++) ((uint8_t *)&desttxid)[i] = opret[4 + 32 + i]; if ( 0 && *heightp != 2690 ) fprintf(stderr," ntzht.%d %s <- txid.%s size.%d\n",*heightp,(*blockhashp).GetHex().c_str(),(txid).GetHex().c_str(),(int32_t)opret.size()); return(desttxid); } int32_t NSPV_notarizationextract(int32_t verifyntz,int32_t *ntzheightp,uint256 *blockhashp,uint256 *desttxidp,CTransaction tx) { int32_t numsigs=0; uint8_t elected[64][33]; char *symbol; std::vector opret; uint32_t nTime; if ( tx.vout.size() >= 2 ) { symbol = (SMART_CHAIN_SYMBOL[0] == 0) ? (char *)"HUSH3" : SMART_CHAIN_SYMBOL; GetOpReturnData(tx.vout[1].scriptPubKey,opret); if ( opret.size() >= 32*2+4 ) { //sleep(1); // needed to avoid no pnodes error *desttxidp = NSPV_opretextract(ntzheightp,blockhashp,symbol,opret,tx.GetHash()); nTime = NSPV_blocktime(*ntzheightp); hush_notaries(elected,*ntzheightp,nTime); if ( verifyntz != 0 && (numsigs= NSPV_fastnotariescount(tx,elected,nTime)) < 12 ) { fprintf(stderr,"numsigs.%d error\n",numsigs); return(-3); } return(0); } else { fprintf(stderr,"opretsize.%d error\n",(int32_t)opret.size()); return(-2); } } else return(-1); } #endif // HUSH_NSPV_H