// 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. * * * ******************************************************************************/ // CCutils has low level functions that are universally useful for all contracts. #include "CCinclude.h" #include "hush_structs.h" #include "key_io.h" #ifdef TESTMODE #define MIN_NON_NOTARIZED_CONFIRMS 2 #else #define MIN_NON_NOTARIZED_CONFIRMS 101 #endif // TESTMODE int32_t hush_dpowconfs(int32_t height,int32_t numconfs); struct hush_state *hush_stateptr(char *symbol,char *dest); extern uint32_t HUSH_DPOWCONFS; 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 } int32_t has_opret(const CTransaction &tx, uint8_t evalcode) { int i = 0; for ( auto vout : tx.vout ) { //fprintf(stderr, "[txid.%s] 1.%i 2.%i 3.%i 4.%i\n",tx.GetHash().GetHex().c_str(), vout.scriptPubKey[0], vout.scriptPubKey[1], vout.scriptPubKey[2], vout.scriptPubKey[3]); if ( vout.scriptPubKey.size() > 3 && vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[2] == evalcode ) return i; i++; } return 0; } bool makeCCopret(CScript &opret, std::vector> &vData) { return false; } CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, std::vector>* vData) { CTxOut vout; return(vout); } CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, std::vector>* vData) { CTxOut vout; return(vout); } bool IsCCInput(CScript const& scriptSig) { return false; } bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime, int64_t &actualtxfee) { LOCK(mempool.cs); CCoinsView dummy; CCoinsViewCache view(&dummy); int64_t interest; uint64_t valuein; CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); view.SetBackend(viewMemPool); valuein = view.GetValueIn(height,&interest,tx,blocktime); actualtxfee = valuein-tx.GetValueOut(); if ( actualtxfee > txfee ) { //fprintf(stderr, "actualtxfee.%li vs txfee.%li\n", actualtxfee, txfee); return false; } return true; } uint32_t GetLatestTimestamp(int32_t height) { if ( HUSH_NSPV_SUPERLITE ) return ((uint32_t)NSPV_blocktime(height)); return(hush_heightstamp(height)); } // :P void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr) { cp->unspendableEvalcode2 = evalcode; cp->unspendablepk2 = pk; memcpy(cp->unspendablepriv2,priv,32); strcpy(cp->unspendableaddr2,coinaddr); } void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr) { cp->unspendableEvalcode3 = evalcode; cp->unspendablepk3 = pk; memcpy(cp->unspendablepriv3,priv,32); strcpy(cp->unspendableaddr3,coinaddr); } void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, uint8_t *priv, char *coinaddr) { cp->coins1of2pk[0] = pk1; cp->coins1of2pk[1] = pk2; memcpy(cp->coins1of2priv,priv,32); strcpy(cp->coins1of2addr,coinaddr); } void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, uint8_t *priv, char *tokenaddr) { cp->tokens1of2pk[0] = pk1; cp->tokens1of2pk[1] = pk2; memcpy(cp->tokens1of2priv,priv,32); strcpy(cp->tokens1of2addr, tokenaddr); } bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) { CTxDestination address; txnouttype whichType; destaddr[0] = 0; if ( scriptPubKey.begin() != 0 ) { if ( ExtractDestination(scriptPubKey,address) != 0 ) { strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str()); return(true); } } //fprintf(stderr,"ExtractDestination failed\n"); return(false); } bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t taddr,uint8_t prefix, uint8_t prefix2) { CTxDestination address; txnouttype whichType; if ( ExtractDestination(scriptPubKey,address) != 0 ) { strcpy(destaddr,(char *)CCustomBitcoinAddress(address,taddr,prefix,prefix2).ToString().c_str()); return(true); } //fprintf(stderr,"ExtractDestination failed\n"); return(false); } bool pubkey2addr(char *destaddr,uint8_t *pubkey33) { std::vectorpk; int32_t i; for (i=0; i<33; i++) pk.push_back(pubkey33[i]); return(Getscriptaddress(destaddr,CScript() << pk << OP_CHECKSIG)); } bool ConstrainVout(CTxOut vout, int32_t CCflag, char *cmpaddr, int64_t nValue) { char destaddr[64]; if ( vout.scriptPubKey.IsPayToCryptoCondition() != CCflag ) { fprintf(stderr,"constrain vout error isCC %d vs %d CCflag\n", vout.scriptPubKey.IsPayToCryptoCondition(), CCflag); return(false); } else if ( cmpaddr != 0 && (Getscriptaddress(destaddr, vout.scriptPubKey) == 0 || strcmp(destaddr, cmpaddr) != 0) ) { fprintf(stderr,"constrain vout error: check addr %s vs script addr %s\n", cmpaddr!=0?cmpaddr:"", destaddr!=0?destaddr:""); return(false); } else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || ( { fprintf(stderr,"constrain vout error nValue %.8f vs %.8f\n",(double)nValue/COIN,(double)vout.nValue/COIN); return(false); } else return(true); } bool priv2addr(char *coinaddr,uint8_t *buf33,uint8_t priv32[32]) { CKey priv; CPubKey pk; int32_t i; uint8_t *src; priv.SetKey32(priv32); pk = priv.GetPubKey(); if ( buf33 != 0 ) { src = (uint8_t *)pk.begin(); for (i=0; i<33; i++) buf33[i] = src[i]; } return(Getscriptaddress(coinaddr, CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG)); } std::vector Mypubkey() { extern uint8_t NOTARY_PUBKEY33[33]; std::vector pubkey; int32_t i; uint8_t *dest,*pubkey33; pubkey33 = NOTARY_PUBKEY33; pubkey.resize(33); dest = pubkey.data(); for (i=0; i<33; i++) dest[i] = pubkey33[i]; return(pubkey); } extern char NSPV_wifstr[],NSPV_pubkeystr[]; extern uint32_t NSPV_logintime; #define NSPV_AUTOLOGOUT 777 bool Myprivkey(uint8_t myprivkey[]) { char coinaddr[64],checkaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret; uint8_t buf33[33]; if ( HUSH_NSPV_SUPERLITE ) { if ( NSPV_logintime == 0 || time(NULL) > NSPV_logintime+NSPV_AUTOLOGOUT ) { fprintf(stderr,"need to be logged in to get myprivkey\n"); return false; } vchSecret = DecodeSecret(NSPV_wifstr); memcpy(myprivkey,vchSecret.begin(),32); //for (i=0; i<32; i++) // fprintf(stderr,"%02x",myprivkey[i]); //fprintf(stderr," myprivkey %s\n",NSPV_wifstr); memset((uint8_t *)vchSecret.begin(),0,32); return true; } if ( Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG) != 0 ) { n = (int32_t)strlen(coinaddr); strAddress.resize(n+1); dest = (char *)strAddress.data(); for (i=0; iGetKey(keyID,vchSecret) != 0 ) { memcpy(myprivkey,vchSecret.begin(),32); memset((uint8_t *)vchSecret.begin(),0,32); if ( 0 ) { for (i=0; i<32; i++) fprintf(stderr,"0x%02x, ",myprivkey[i]); fprintf(stderr," found privkey for %s!\n",dest); } if ( priv2addr(checkaddr,buf33,myprivkey) != 0 ) { if ( buf2pk(buf33) == Mypubkey() && strcmp(checkaddr,coinaddr) == 0 ) return(true); else printf("mismatched privkey -> addr %s vs %s\n",checkaddr,coinaddr); } return(false); } #endif } } fprintf(stderr,"privkey for the -pubkey= address is not in the wallet, importprivkey!\n"); return(false); } CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv) { if ( unspendablepriv != 0 ) memcpy(unspendablepriv,cp->CCpriv,32); return(pubkey2pk(ParseHex(cp->CChexstr))); } int32_t NSPV_coinaddr_inmempool(char const *logcategory,char *coinaddr,uint8_t CCflag); int32_t myIs_coinaddr_inmempoolvout(char const *logcategory,char *coinaddr) { int32_t i,n; char destaddr[64]; if ( HUSH_NSPV_SUPERLITE ) return(NSPV_coinaddr_inmempool(logcategory,coinaddr,1)); BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) { const CTransaction &tx = e.GetTx(); if ( (n= tx.vout.size()) > 0 ) { const uint256 &txid = tx.GetHash(); for (i=0; i &txs,uint8_t evalcode,uint8_t funcid) { int i=0; if ( HUSH_NSPV_SUPERLITE ) { CTransaction tx; uint256 hashBlock; NSPV_evalcode_inmempool(evalcode,funcid); for (int i=0;i &proofData, std::vector &txids) { CMerkleBlock merkleBlock; if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) return uint256(); return merkleBlock.txn.ExtractMatches(txids); } extern struct NSPV_inforesp NSPV_inforesult; int32_t hush_get_current_height() { if ( HUSH_NSPV_SUPERLITE ) { return (NSPV_inforesult.height); } else return chainActive.LastTip()->GetHeight(); } bool hush_txnotarizedconfirmed(uint256 txid) { char str[65]; int32_t confirms,notarized=0,txheight=0,currentheight=0;; CTransaction tx; uint256 hashBlock; CBlockIndex *pindex; char symbol[HUSH_SMART_CHAIN_MAXLEN],dest[HUSH_SMART_CHAIN_MAXLEN]; struct hush_state *sp; if ( HUSH_NSPV_SUPERLITE ) { if ( NSPV_myGetTransaction(txid,tx,hashBlock,txheight,currentheight) == 0 ) { fprintf(stderr,"hush_txnotarizedconfirmed cant find txid %s\n",txid.ToString().c_str()); return(0); } else if (txheight<=0) { fprintf(stderr,"hush_txnotarizedconfirmed no txheight.%d for txid %s\n",txheight,txid.ToString().c_str()); return(0); } else if (txheight>currentheight) { fprintf(stderr,"hush_txnotarizedconfirmed backwards heights for txid %s hts.(%d %d)\n",txid.ToString().c_str(),txheight,currentheight); return(0); } confirms=1 + currentheight - txheight; } else { if ( myGetTransaction(txid,tx,hashBlock) == 0 ) { fprintf(stderr,"hush_txnotarizedconfirmed cant find txid %s\n",txid.ToString().c_str()); return(0); } else if ( hashBlock == zeroid ) { fprintf(stderr,"hush_txnotarizedconfirmed no hashBlock for txid %s\n",txid.ToString().c_str()); return(0); } else if ( (pindex= hush_blockindex(hashBlock)) == 0 || (txheight= pindex->GetHeight()) <= 0 ) { fprintf(stderr,"hush_txnotarizedconfirmed no txheight.%d %p for txid %s\n",txheight,pindex,txid.ToString().c_str()); return(0); } else if ( (pindex= chainActive.LastTip()) == 0 || pindex->GetHeight() < txheight ) { fprintf(stderr,"hush_txnotarizedconfirmed backwards heights for txid %s hts.(%d %d)\n",txid.ToString().c_str(),txheight,(int32_t)pindex->GetHeight()); return(0); } confirms=1 + pindex->GetHeight() - txheight; } if ((sp= hush_stateptr(symbol,dest)) != 0 && (notarized=sp->NOTARIZED_HEIGHT) > 0 && txheight > sp->NOTARIZED_HEIGHT) notarized=0; #ifdef TESTMODE notarized=0; #endif //TESTMODE if (notarized>0 && confirms > 1) return (true); else if (notarized==0 && confirms >= MIN_NON_NOTARIZED_CONFIRMS) return (true); return (false); } // returns total of normal inputs signed with this pubkey int64_t TotalPubkeyNormalInputs(const CTransaction &tx, const CPubKey &pubkey) { int64_t total = 0; for (auto vin : tx.vin) { CTransaction vintx; uint256 hashBlock; if (!IsCCInput(vin.scriptSig) && myGetTransaction(vin.prevout.hash, vintx, hashBlock)) { typedef std::vector valtype; std::vector vSolutions; txnouttype whichType; if (Solver(vintx.vout[vin.prevout.n].scriptPubKey, whichType, vSolutions)) { switch (whichType) { case TX_PUBKEY: if (pubkey == CPubKey(vSolutions[0])) // is my input? total += vintx.vout[vin.prevout.n].nValue; break; case TX_PUBKEYHASH: if (pubkey.GetID() == CKeyID(uint160(vSolutions[0]))) // is my input? total += vintx.vout[vin.prevout.n].nValue; break; } } } } return total; } // returns total of CC inputs signed with this pubkey int64_t TotalPubkeyCCInputs(const CTransaction &tx, const CPubKey &pubkey) { int64_t total = 0; return total; } extern struct CCcontract_info CCinfos[0x100]; extern std::string MYCCLIBNAME; bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx,unsigned int nIn);