diff --git a/src/komodo_nSPV.h b/src/komodo_nSPV.h index d3d17221b..4936c777d 100644 --- a/src/komodo_nSPV.h +++ b/src/komodo_nSPV.h @@ -806,22 +806,28 @@ void komodo_nSPVreq(CNode *pfrom,std::vector request) // received a req // nSPV client. VERY simplistic "single threaded" networking model. for production GUI best to multithread, etc. #define NSPV_POLLITERS 15 #define NSPV_POLLMICROS 100000 +#define NSPV_MAXVINS 64 CAmount AmountFromValue(const UniValue& value); int32_t bitcoin_base58decode(uint8_t *data,char *coinaddr); uint32_t NSPV_lastinfo,NSPV_logintime; -char NSPV_wifstr[64]; +char NSPV_wifstr[64],NSPV_pubkeystr[67]; std::string NSPV_address; +CKey NSPV_key; struct NSPV_inforesp NSPV_inforesult; struct NSPV_utxosresp NSPV_utxosresult; struct NSPV_spentinfo NSPV_spentresult; struct NSPV_ntzsresp NSPV_ntzsresult; struct NSPV_ntzsproofresp NSPV_ntzsproofresult; struct NSPV_txproof NSPV_txproofresult; - struct NSPV_utxo *NSPV_utxos; +CKey *NSPV_defaultkey() +{ + return(&NSPV_key); +} + CNode *NSPV_req(CNode *pnode,uint8_t *msg,int32_t len,uint64_t mask,int32_t ind) { int32_t flag = 0; uint32_t timestamp = (uint32_t)time(NULL); @@ -990,13 +996,13 @@ UniValue NSPV_login(char *wifstr) NSPV_logintime = (uint32_t)time(NULL); result.push_back(Pair("result","success")); result.push_back(Pair("status","wif will expire in 60 seconds")); - CKey key = DecodeSecret(wifstr); - CPubKey pubkey = key.GetPubKey(); - //assert(key.VerifyPubKey(pubkey)); + NSPV_key = DecodeSecret(wifstr); + 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()); 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)); @@ -1187,6 +1193,199 @@ void komodo_nSPVresp(CNode *pfrom,std::vector response) // received a r } } +int32_t NSPV_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *belowp,struct NSPV_utxoresp utxos[],int32_t numunspents,int64_t value) +{ + int32_t i,abovei,belowi; int64_t above,below,gap,atx_value; + abovei = belowi = -1; + for (above=below=i=0; i value ) + { + gap = (atx_value - value); + if ( above == 0 || gap < above ) + { + above = gap; + abovei = i; + } + } + else + { + gap = (value - atx_value); + if ( below == 0 || gap < below ) + { + below = gap; + belowi = i; + } + } + //printf("value %.8f gap %.8f abovei.%d %.8f belowi.%d %.8f\n",dstr(value),dstr(gap),abovei,dstr(above),belowi,dstr(below)); + } + *aboveip = abovei; + *abovep = above; + *belowip = belowi; + *belowp = below; + //printf("above.%d below.%d\n",abovei,belowi); + if ( abovei >= 0 && belowi >= 0 ) + { + if ( above < (below >> 1) ) + return(abovei); + else return(belowi); + } + else if ( abovei >= 0 ) + return(abovei); + else return(belowi); +} + +int64_t NSPV_addinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs) +{ + int32_t abovei,belowi,ind,vout,i,n = 0; int64_t threshold,above,below; int64_t remains,totalinputs = 0; CTransaction tx; struct NSPV_utxoresp *utxos,*up; + utxos = (struct NSPV_utxoresp *)calloc(NSPV_MAXVINS,sizeof(*utxos)); + if ( maxinputs > NSPV_MAXVINS ) + maxinputs = NSPV_MAXVINS; + if ( maxinputs > 0 ) + threshold = total/maxinputs; + else threshold = total; + remains = total; + for (i=0; i0; i++) + { + below = above = 0; + abovei = belowi = -1; + if ( NSPV_vinselect(&abovei,&above,&belowi,&below,utxos,n,remains) < 0 ) + { + printf("error finding unspent i.%d of %d, %.8f vs %.8f\n",i,n,(double)remains/COIN,(double)total/COIN); + free(utxos); + return(0); + } + if ( belowi < 0 || abovei >= 0 ) + ind = abovei; + else ind = belowi; + if ( ind < 0 ) + { + printf("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); + free(utxos); + return(0); + } + up = &utxos[ind]; + mtx.vin.push_back(CTxIn(up->txid,up->vout,CScript())); + totalinputs += up->nValue; + remains -= up->nValue; + 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); + if ( totalinputs >= total || (i+1) >= maxinputs ) + break; + } + free(utxos); + if ( totalinputs >= total ) + return(totalinputs); + return(0); +} + +std::string NSPV_signtx(CMutableTransaction &mtx,uint64_t txfee,CScript opret) +{ + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + CTransaction vintx; std::string hex; uint256 hashBlock; int64_t change,totaloutputs=0,totalinputs=0; int32_t i,utxovout,n; + n = mtx.vout.size(); + for (i=0; i= totaloutputs+2*txfee ) + { + change = totalinputs - (totaloutputs+txfee); + mtx.vout.push_back(CTxOut(change,CScript() << ParseHex(NSPV_pubkeystr) << OP_CHECKSIG)); + } + if ( opret.size() > 0 ) + mtx.vout.push_back(CTxOut(0,opret)); + PrecomputedTransactionData txdata(mtx); + n = mtx.vin.size(); + for (i=0; i data,opret; std::string hex; + data.resize(20); + memcpy(&data[0],&rmd160[1],20); + if ( NSPV_addinputs(mtx,satoshis+txfee,64) > 0 ) + { + mtx.vout.push_back(CTxOut(nValue,CScript() << OP_DUP << OP_HASH160 << ParseHex(HexStr(data)) << OP_EQUALVERIFY << OP_CHECKSIG)); + hex = NSPV_signt(mtx,txfee,opret); + result.push_back(Pair("result","success")); + result.push_back(Pair("hex",hex)); + // prove all the vins + return(result); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt create tx")); + return(result); + } +} + void komodo_nSPV(CNode *pto) // polling loop from SendMessages { uint8_t msg[256]; int32_t i,len=0; uint32_t timestamp = (uint32_t)time(NULL); @@ -1194,43 +1393,11 @@ void komodo_nSPV(CNode *pto) // polling loop from SendMessages { fprintf(stderr,"scrub wif from NSPV memory\n"); memset(NSPV_wifstr,0,sizeof(NSPV_wifstr)); + memset(&NSPV_key,0,sizeof(NSPV_key)); NSPV_logintime = 0; } if ( (pto->nServices & NODE_NSPV) == 0 ) return; - /*if ( timestamp > pto->lastntzs || timestamp > pto->lastproof ) - { - for (i=0; i pto->lastntzs ) - { - request[0] = NSPV_NTZS; - pto->lastntzs = timestamp; - pto->PushMessage("getnSPV",request); - return; - } - else if ( timestamp > pto->lastproof ) - { - if ( NSPV_utxos[i].T.txlen == 0 ) - { - request[0] = NSPV_TXPROOF; - pto->lastproof = timestamp; - pto->PushMessage("getnSPV",request); - } - else // need space for the headers... - { - request[0] = NSPV_NTZPROOF; - pto->lastproof = timestamp; - pto->PushMessage("getnSPV",request); - } - return; - } - } - } - }*/ if ( KOMODO_NSPV != 0 ) { if ( timestamp > NSPV_lastinfo + ASSETCHAINS_BLOCKTIME/2 && timestamp > pto->prevtimes[NSPV_INFO>>1] + 2*ASSETCHAINS_BLOCKTIME/3 ) @@ -1242,8 +1409,4 @@ void komodo_nSPV(CNode *pto) // polling loop from SendMessages } } -UniValue NSPV_send(char *srcaddr,char *destaddr,int64_t satoshis) // what its all about! -{ - -} #endif // KOMODO_NSPV_H diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 685018828..fbc01669b 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -37,6 +37,7 @@ typedef vector valtype; extern uint8_t ASSETCHAINS_TXPOW; TransactionSignatureCreator::TransactionSignatureCreator(const CKeyStore* keystoreIn, const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, int nHashTypeIn) : BaseSignatureCreator(keystoreIn), txTo(txToIn), nIn(nInIn), nHashType(nHashTypeIn), amount(amountIn), checker(txTo, nIn, amountIn) {} +CKey *NSPV_defaultkey(); bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, const CKeyID& address, const CScript& scriptCode, uint32_t consensusBranchId, CKey *pprivKey, void *extraData) const { @@ -44,7 +45,11 @@ bool TransactionSignatureCreator::CreateSig(std::vector& vchSig, if (pprivKey) key = *pprivKey; else if (!keystore || !keystore->GetKey(address, key)) - return false; + { + if ( (pprivKey= NSPV_defaultkey()) == 0 ) + return false; + else key = *pprivKey; + } uint256 hash; try {