Hush Full Node software. We were censored from Github, this is where all development happens now. https://hush.is
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

461 lines
16 KiB

// 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<std::vector<unsigned char>> &vData)
{
return false;
}
CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, std::vector<std::vector<unsigned char>>* vData)
{
CTxOut vout;
return(vout);
}
CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, std::vector<std::vector<unsigned char>>* 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::vector<uint8_t>pk; 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<uint8_t> Mypubkey()
{
extern uint8_t NOTARY_PUBKEY33[33];
std::vector<uint8_t> 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; i<n; i++)
dest[i] = coinaddr[i];
dest[i] = 0;
if ( address.SetString(strAddress) != 0 && address.GetKeyID(keyID) != 0 )
{
#ifdef ENABLE_WALLET
if ( pwalletMain->GetKey(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<n; i++)
{
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
if ( strcmp(destaddr,coinaddr) == 0 )
{
LogPrint(logcategory,"found (%s) vout in mempool\n",coinaddr);
return(1);
}
}
}
}
return(0);
}
extern struct NSPV_mempoolresp NSPV_mempoolresult;
extern bool NSPV_evalcode_inmempool(uint8_t evalcode,uint8_t funcid);
int32_t myGet_mempool_txs(std::vector<CTransaction> &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<NSPV_mempoolresult.numtxids;i++)
{
if (myGetTransaction(NSPV_mempoolresult.txids[i],tx,hashBlock)!=0) txs.push_back(tx);
}
return (NSPV_mempoolresult.numtxids);
}
BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx)
{
txs.push_back(e.GetTx());
i++;
}
return(i);
}
/* Get the block merkle root for a proof
* IN: proofData
* OUT: merkle root
* OUT: transaction IDS
*/
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &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<unsigned char> valtype;
std::vector<valtype> 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);