diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 0fa2ae68a..35dae0adb 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -28,18 +28,9 @@ #include "core_io.h" #define FAUCET2SIZE COIN #define EVAL_FAUCET2 EVAL_FIRSTUSER -#ifdef BUILD_ROGUE -#define EVAL_ROGUE 17 -std::string MYCCLIBNAME = (char *)"rogue"; -#elif BUILD_CUSTOMCC +#ifdef BUILD_CUSTOMCC #include "customcc.h" - -#else -#define EVAL_SUDOKU 17 -#define EVAL_MUSIG 18 -#define EVAL_DILITHIUM 19 -std::string MYCCLIBNAME = (char *)"sudoku"; #endif #ifndef BUILD_GAMESCC @@ -147,74 +138,16 @@ int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds) { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,cclibpk; CScript opret; - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - cclibpk = GetUnspendable(cp,0); - if ( AddNormalinputs2(mtx,funds+txfee,64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,cclibpk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); - } return(""); } std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params) { - CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight()); - CPubKey mypk,cclibpk; int64_t funds,txfee=0,inputs,CCchange=0,nValue=FAUCET2SIZE; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; - if ( txfee == 0 ) - txfee = 10000; - if ( funcid == 'F' ) - { - if ( cJSON_GetArraySize(params) > 0 ) - { - funds = (int64_t)jdouble(jitem(params,0),0)*COIN + 0.0000000049; - return(Faucet2Fund(cp,0,funds)); - } else return(""); - } - else if ( funcid != 'G' ) - return(""); - cclibpk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddCClibInputs(cp,mtx,cclibpk,nValue+txfee,60,cp->unspendableCCaddr,1)) > 0 ) - { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET2,CCchange,cclibpk)); - mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - fprintf(stderr,"start at %u\n",(uint32_t)time(NULL)); - j = rand() & 0xfffffff; - for (i=0; i<1000000; i++,j++) - { - tmpmtx = mtx; - rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_FAUCET2 << (uint8_t)'G' << j)); - if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 ) - { - len >>= 1; - decode_hex(buf,len,(char *)rawhex.c_str()); - hash = bits256_doublesha256(0,buf,len); - if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 ) - { - fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL)); - return(rawhex); - } - //fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]); - } - } - fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL)); - return(""); - } else fprintf(stderr,"cant find faucet inputs\n"); return(""); } UniValue cclib_error(UniValue &result,const char *errorstr) { - result.push_back(Pair("status","error")); - result.push_back(Pair("error",errorstr)); return(result); } @@ -227,12 +160,7 @@ uint256 juint256(cJSON *obj) int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len) { - char *hexstr; - if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == len*2 ) - { - decode_hex(hash32,len,hexstr); - return(0); - } else return(-1); + return(0); } diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h deleted file mode 100644 index 4e0a24668..000000000 --- a/src/cc/heir_validate.h +++ /dev/null @@ -1,679 +0,0 @@ -// Copyright (c) 2016-2023 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 -#ifndef HEIR_VALIDATE_H -#define HEIR_VALIDATE_H - -#include "CCinclude.h" -#include "CCHeir.h" - -#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos) - -// makes coin initial tx opret -vscript_t EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo); -vscript_t EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); - -uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan); -//uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false); -//uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); -uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging = false); -uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging = false); - -inline static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); } -inline static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } - -// helper class to allow polymorphic behaviour for HeirXXX() functions in case of coins -class CoinHelper { -public: - - static uint8_t getMyEval() { return EVAL_HEIR; } - static int64_t addOwnerInputs(uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { - return AddNormalinputs(mtx, ownerPubkey, total, maxinputs); - } - - static CScript makeCreateOpRet(uint256 dummyid, std::vector dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { - return CScript() << OP_RETURN << EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo); - } - static CScript makeAddOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return CScript() << OP_RETURN << EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan); - } - static CScript makeClaimOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return CScript() << OP_RETURN << EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan); - } - static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) { - return MakeCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey); - } - static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) { - return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG); - } - /* static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) { - return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG); - } */ - static bool GetCoinsOrTokensCCaddress1of2(char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) { - struct CCcontract_info *cpHeir, heirC; - cpHeir = CCinit(&heirC, EVAL_HEIR); - return GetCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey); - } - static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) - { - uint8_t mypriv[32]; - Myprivkey(mypriv); - CCaddr1of2set(cp, ownerPubkey, heirPubkey,mypriv, coinaddr); - memset(mypriv,0,sizeof(mypriv)); - } -}; - -// helper class to allow polymorphic behaviour for HeirXXX() functions in case of tokens -class TokenHelper { -public: - static uint8_t getMyEval() { return EVAL_TOKENS; } - static int64_t addOwnerInputs(uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { - /* - struct CCcontract_info *cpHeir, heirC; - cpHeir = CCinit(&heirC, EVAL_TOKENS); - return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs); - */ - return 0; - } - - static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) { - return EncodeTokenOpRet(tokenid, voutTokenPubkeys, - std::make_pair(OPRETID_HEIRDATA, EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo))); - } - static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeTokenOpRet(tokenid, voutTokenPubkeys, - std::make_pair(OPRETID_HEIRDATA, EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan))); - } - static CScript makeClaimOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeTokenOpRet(tokenid, voutTokenPubkeys, - std::make_pair(OPRETID_HEIRDATA, EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan))); - } - - static CTxOut make1of2Vout(int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey) { - return MakeTokensCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey); - } - static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) { - return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); // yes EVAL_TOKENS - } - /* static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) { - return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); // yes EVAL_TOKENS - } */ - static bool GetCoinsOrTokensCCaddress1of2(char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) { - struct CCcontract_info *cpHeir, heirC; - cpHeir = CCinit(&heirC, EVAL_HEIR); - return GetTokensCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey); - } - - static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { - uint8_t mypriv[32]; - Myprivkey(mypriv); - CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, mypriv, coinaddr); - memset(mypriv,0,sizeof(mypriv)); - } -}; - - -/** - * Small framework for vins and vouts validation implementing a variation of 'chain of responsibility' pattern: - * It consists of two classes CInputValidationPlan and COutputValidationPlan which both are configured with an array of vectors of validators - * (These validators are derived from the class CValidatorBase). - * - * A example of a validator may verify for a vout if its public key corresponds to the public key which is stored in opreturn. - * Or, vin validator may check if this vin depicts correctly to the CC contract's address. - * - * For validating vins CInputValidator additionally is provided with an instance of a class derived from the CInputIdentifierBase class. - * this identifier class allows to select identical vins (for example, normal vins or cc input vins) and apply validators from the corresponding vector to it. - * Note: CInputValidator treats that at least one identified vin should be present, otherwise it returns eval->invalid() and false. - * - * For validating vouts COutputValidator is configured for each vector of validators with the vout index to which these validators are applied - * (see constructors of both CInputValidator and COutputValidator) - */ - -/** - * base class for all validators - */ -class CValidatorBase -{ -public: - CValidatorBase(CCcontract_info* cp) : m_cp(cp) {} - virtual bool isVinValidator() const = 0; - virtual bool validateVin(CTxIn vin, std::vector prevVout, int32_t prevN, std::string& message) const = 0; - virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const = 0; - -protected: - CCcontract_info * m_cp; -}; - -/** - * Base class for classes which identify vins as normal or cc inputs - */ -class CInputIdentifierBase -{ -public: - CInputIdentifierBase(CCcontract_info* cp) : m_cp(cp) {} - virtual std::string inputName() const = 0; - virtual bool identifyInput(CTxIn vin) const = 0; -protected: - CCcontract_info * m_cp; -}; - -/** - * Encapsulates an array containing rows of validators - * Each row is a vector of validators (zero is possible) for validating vins or prev tx's vouts - * this validation plan is used for validating tx inputs - */ -template -class CInputValidationPlan -{ - using ValidatorsRow = std::vector; - -public: - - // Pushes a row of validators for validating a vin or vout - // @param CInputIdentifierBase* pointer to class-identifier which determines several identical adjacent vins (like in schema "vin.0+: normal inputs") - // @param pargs parameter pack of zero or more pointer to validator objects - // Why pointers? because we store the base class in validators' row and then call its virtual functions - template - void pushValidators(CInputIdentifierBase *identifier, ARGS*... pargs) // validators row passed as variadic arguments CValidatorX *val1, CValidatorY *val2 ... - { - ValidatorsRow vValidators({ (TValidatorBase*)pargs... }); - m_arrayValidators.push_back(std::make_pair(identifier, vValidators)); - } - - // validate tx inputs and corresponding prev tx vouts - bool validate(const CTransaction& tx, Eval* eval) - { - std::string message = ""; - //std::cerr << "CInputValidationPlan::validate() starting vins validation..." << std::endl; - - int32_t ival = 0; - int32_t iv = 0; - int32_t numv = tx.vin.size(); - int32_t numValidators = m_arrayValidators.size(); - - // run over vins: - while (iv < numv && ival < numValidators) { - - int32_t identifiedCount = 0; - CInputIdentifierBase *identifier = m_arrayValidators[ival].first; - // check if this is 'our' input: - while (iv < numv && identifier->identifyInput(tx.vin[iv])) { - - // get prev tx: - CTransaction prevTx, *pPrevTxOrNull = NULL; - uint256 hashBlock; - - if (!eval->GetTxUnconfirmed(tx.vin[iv].prevout.hash, prevTx, hashBlock)) { - std::ostringstream stream; - stream << "can't find vinTx for vin=" << iv << "."; - return eval->Invalid(stream.str().c_str()); - } - pPrevTxOrNull = &prevTx; // TODO: get prev tx only if it required (i.e. if vout validators are present) - - // exec 'validators' from validator row of ival index, for tx.vin[iv] - if (!execValidatorsInRow(&tx, pPrevTxOrNull, iv, ival, message)) { - std::ostringstream stream; - stream << "invalid tx vin[" << iv << "]:" << message; - return eval->Invalid(stream.str().c_str()); // ... if not, return 'invalid' - } - - identifiedCount++; // how many vins we identified - iv++; // advance to the next vin - } - - // CInputValidationPlan treats that there must be at least one identified vin for configured validators' row - // like in 'vin.0: normal input' - if (identifiedCount == 0) { - std::ostringstream stream; - stream << "can't find required vins for " << identifier->inputName() << "."; - return eval->Invalid(stream.str().c_str()); - } - - ival++; // advance to the next validator row - // and it will try the same vin with the new CInputIdentifierBase and validators row - } - - // validation is successful if all validators have been used (i.e. ival = numValidators) - if (ival < numValidators) { - std::cerr << "CInputValidationPlan::validate() incorrect tx" << " ival=" << ival << " numValidators=" << numValidators << std::endl; - return eval->Invalid("incorrect tx structure: not all required vins are present."); - } - - //std::cerr << "CInputValidationPlan::validate() returns with true" << std::endl; - return true; - } - -private: - // Executes validators from the requested row of validators (selected by iValidators) for selected vin or vout (selected by iv) - bool execValidatorsInRow(const CTransaction* pTx, const CTransaction* pPrevTx, int32_t iv, int32_t ival, std::string& refMessage) const - { - // check boundaries: - if (ival < 0 || ival >= m_arrayValidators.size()) { - std::cerr << "CInputValidationPlan::execValidatorsInRow() internal error: incorrect param ival=" << ival << " size=" << m_arrayValidators.size(); - refMessage = "internal error: incorrect param ival index"; - return false; - } - - if (iv < 0 || iv >= pTx->vin.size()) { - std::cerr << "CInputValidationPlan::execValidatorsInRow() internal error: incorrect param iv=" << iv << " size=" << m_arrayValidators.size(); - refMessage = "internal error: incorrect param iv index"; - return false; - } - - // get requested row of validators: - ValidatorsRow vValidators = m_arrayValidators[ival].second; - - //std::cerr << "CInputValidationPlan::execValidatorsInRow() calling validators" << " for vin iv=" << iv << " ival=" << ival << std::endl; - - for (auto v : vValidators) { - bool result; - - if (v->isVinValidator()) - // validate this vin and previous vout: - result = v->validateVin(pTx->vin[iv], pPrevTx->vout, pTx->vin[iv].prevout.n, refMessage); - else - // if it is vout validator pass the previous tx vout: - result = v->validateVout( pPrevTx->vout[pTx->vin[iv].prevout.n], pTx->vin[iv].prevout.n, refMessage); - if (!result) { - return result; - } - } - return true; // validation OK - } - - -private: - //std::map m_arrayValidators; - std::vector< std::pair > m_arrayValidators; - -}; - - -/** - * Encapsulates an array containing rows of validators - * Each row is a vector of validators (zero is possible) for validating vouts - * this validation plan is used for validating tx outputs - */ -template -class COutputValidationPlan -{ - using ValidatorsRow = std::vector; - -public: - // Pushes a row of validators for validating a vout - // @param ivout index to vout to validate - // @param pargs parameter pack of zero or more pointer to validator objects - // Why pointers? because we store base class and call its virtual functions - - template - void pushValidators(int32_t ivout, ARGS*... pargs) // validators row passed as variadic arguments CValidatorX *val1, CValidatorY *val2 ... - { - ValidatorsRow vValidators({ (TValidatorBase*)pargs... }); - m_arrayValidators.push_back(std::make_pair(ivout, vValidators)); - } - - // validate tx outputs - bool validate(const CTransaction& tx, Eval* eval) - { - std::string message = ""; - //std::cerr << "COutputValidationPlan::validateOutputs() starting vouts validation..." << std::endl; - - int32_t ival = 0; - int32_t numVouts = tx.vout.size(); - int32_t numValidators = m_arrayValidators.size(); - - // run over vouts: - while (ival < numValidators) { - - int32_t ivout = m_arrayValidators[ival].first; - if (ivout >= numVouts) { - std::cerr << "COutputValidationPlan::validate() incorrect tx" << "for ival=" << ival << " in tx.vout no such ivout=" << ivout << std::endl; - return eval->Invalid("incorrect tx structure: not all required vouts are present."); - } - else - { - // exec 'validators' from validator row of ival index, for tx.vout[ivout] - if (!execValidatorsInRow(&tx, ivout, ival, message)) { - std::ostringstream stream; - stream << "invalid tx vout[" << ivout << "]:" << message; - return eval->Invalid(stream.str().c_str()); // ... if not, return 'invalid' - } - } - ival++; // advance to the next vout - } - //std::cerr << "COutputValidationPlan::validate() returns with true" << std::endl; - return true; - } - -private: - // Executes validators from the requested row of validators (selected by iValidators) for selected vin or vout (selected by iv) - bool execValidatorsInRow(const CTransaction* pTx, int32_t iv, int32_t ival, std::string& refMessage) const - { - // check boundaries: - if (ival < 0 || ival >= m_arrayValidators.size()) { - std::cerr << "COutputValidationPlan::execValidatorsInRow() internal error: incorrect param ival=" << ival << " size=" << m_arrayValidators.size(); - refMessage = "internal error: incorrect param ival index"; - return false; - } - - if (iv < 0 || iv >= pTx->vout.size()) { - std::cerr << "COutputValidationPlan::execValidatorsInRow() internal error: incorrect param iv=" << iv << " size=" << m_arrayValidators.size(); - refMessage = "internal error: incorrect param iv index"; - return false; - } - - // get requested row of validators: - ValidatorsRow vValidators = m_arrayValidators[ival].second; - - //std::cerr << "COutputValidationPlan::execRow() calling validators" << " for vout iv=" << iv << " ival=" << ival << std::endl; - - for (auto v : vValidators) { - - if (!v->isVinValidator()) { - // if this is a 'in' validation plan then pass the previous tx vout: - bool result = v->validateVout(pTx->vout[iv], iv, refMessage); - if (!result) - return result; - } - } - return true; // validation OK - } - -private: - //std::map m_mapValidators; - std::vector< std::pair > m_arrayValidators; - -}; - -class CNormalInputIdentifier : CInputIdentifierBase { -public: - CNormalInputIdentifier(CCcontract_info* cp) : CInputIdentifierBase(cp) {} - virtual std::string inputName() const { return std::string("normal input"); } - virtual bool identifyInput(CTxIn vin) const { - return !IsCCInput(vin.scriptSig); - } -}; - -class CCCInputIdentifier : CInputIdentifierBase { -public: - CCCInputIdentifier(CCcontract_info* cp) : CInputIdentifierBase(cp) {} - virtual std::string inputName() const { return std::string("CC input"); } - virtual bool identifyInput(CTxIn vin) const { - return IsCCInput(vin.scriptSig); - } -}; - - -/** - * Validates 1of2address for vout (may be used for either this or prev tx) - */ -template class CCC1of2AddressValidator : CValidatorBase -{ -public: - CCC1of2AddressValidator(CCcontract_info* cp, CScript opRetScript, std::string customMessage = "") : - m_fundingOpretScript(opRetScript), m_customMessage(customMessage), CValidatorBase(cp) {} - - virtual bool isVinValidator() const { return false; } - virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const - { - //std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl; - CPubKey ownerPubkey, heirPubkey; - int64_t inactivityTime; - std::string heirName, memo; - uint256 tokenid; - - uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); - if (funcId == 0) { - message = m_customMessage + std::string(" invalid opreturn format"); - std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; - return false; - } - - char shouldBeAddr[65], ccAddr[65]; - - //GetCCaddress1of2(m_cp, shouldBeAddr, ownerPubkey, heirPubkey); - Helper::GetCoinsOrTokensCCaddress1of2(shouldBeAddr, ownerPubkey, heirPubkey); - - if (vout.scriptPubKey.IsPayToCryptoCondition()) { - if (Getscriptaddress(ccAddr, vout.scriptPubKey) && strcmp(shouldBeAddr, ccAddr) == 0) { - //std::cerr << "CCC1of2AddressValidator::validateVout() exits with true" << std::endl; - return true; - } - else { - message = m_customMessage + std::string(" incorrect heir funding address: incorrect pubkey(s)"); - } - } - else { - message = m_customMessage + std::string(" incorrect heir funding address: not a 1of2addr"); - } - - std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; - return false; - } - virtual bool validateVin(CTxIn vin, std::vector prevVout, int32_t prevN, std::string& message) const { return false; } - -private: - CScript m_fundingOpretScript; - std::string m_customMessage; -}; - - -/** - * Validates if this is vout to owner or heir from opret (funding or change) - */ -template class CMyPubkeyVoutValidator : CValidatorBase -{ -public: - CMyPubkeyVoutValidator(CCcontract_info* cp, CScript opRetScript, bool checkNormals) - : m_fundingOpretScript(opRetScript), m_checkNormals(checkNormals), CValidatorBase(cp) { } - - virtual bool isVinValidator() const { return false; } - virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const - { - //std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl; - - CPubKey ownerPubkey, heirPubkey; - int64_t inactivityTime; - std::string heirName, memo; - uint256 tokenid; - - ///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl; - - // get both pubkeys: - uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); - if (funcId == 0) { - message = std::string("invalid opreturn format"); - return false; - } - - CScript ownerScript; - CScript heirScript; - if (m_checkNormals) { //not used, incorrect check, too strict - ownerScript = CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey; - heirScript = CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey; - std::cerr << "CMyPubkeyVoutValidator::validateVout() vout.scriptPubKey=" << vout.scriptPubKey.ToString() << " makeUserVout(coin,owner)=" << CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey.ToString() << " makeUserVout(coin,heir)=" << CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey.ToString() << std::endl; - } - else { - ownerScript = Helper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey; - heirScript = Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey; - std::cerr << "CMyPubkeyVoutValidator::validateVout() vout.scriptPubKey=" << vout.scriptPubKey.ToString() << " makeUserVout(owner)=" << Helper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey.ToString() << " makeUserVout(heir)=" << Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey.ToString() << std::endl; - } - - // recreate scriptPubKey for owner and heir and compare it with that of the vout to check: - if (vout.scriptPubKey == ownerScript || vout.scriptPubKey == heirScript) { - // this is vout to owner or heir addr: - //std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with true" << std::endl; - return true; - } - - std::cerr << "CMyPubkeyVoutValidator::validateVout() exits with false (not the owner's or heir's addresses)" << std::endl; - message = std::string("invalid pubkey"); - return false; - } - virtual bool validateVin(CTxIn vin, std::vector prevVout, int32_t prevN, std::string& message) const { return true; } - -private: - CScript m_fundingOpretScript; - //uint256 m_lasttxid; - bool m_checkNormals; -}; - -/** - * Check if the user is the heir and the heir is allowed to spend (duration > inactivityTime) - */ -template class CHeirSpendValidator : CValidatorBase -{ -public: - CHeirSpendValidator(CCcontract_info* cp, CScript opRetScript, uint256 latesttxid, uint8_t isHeirSpendingBegan) - : m_fundingOpretScript(opRetScript), m_latesttxid(latesttxid), m_isHeirSpendingBegan(isHeirSpendingBegan), CValidatorBase(cp) {} - - virtual bool isVinValidator() const { return false; } - virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const - { - //std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl; - - CPubKey ownerPubkey, heirPubkey; - int64_t inactivityTime; - std::string heirName, memo; - uint256 tokenid; - - // get heir pubkey: - uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true); - if (funcId == 0) { - message = std::string("invalid opreturn format"); - return false; - } - - int32_t numblocks; - int64_t durationSec = CCduration(numblocks, m_latesttxid); - - // recreate scriptPubKey for heir and compare it with that of the vout: - if (vout.scriptPubKey == Helper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey) { - // this is the heir is trying to spend - if (!m_isHeirSpendingBegan && durationSec <= inactivityTime) { - message = "heir is not allowed yet to spend funds"; - std::cerr << "CHeirSpendValidator::validateVout() heir is not allowed yet to spend funds" << std::endl; - return false; - } - else { - // heir is allowed to spend - return true; - } - } - - //std::cerr << "CHeirSpendValidator::validateVout() exits with true" << std::endl; - - // this is not heir: - return true; - } - virtual bool validateVin(CTxIn vin, std::vector prevVout, int32_t prevN, std::string& message) const { return true; } - -private: - CScript m_fundingOpretScript; - uint256 m_latesttxid; - uint8_t m_isHeirSpendingBegan; -}; - -/** - * Validates this opreturn and compares it with the opreturn from the previous tx - */ -template class COpRetValidator : CValidatorBase -{ -public: - COpRetValidator(CCcontract_info* cp, CScript opret) - : m_fundingOpretScript(opret), CValidatorBase(cp) {} - - virtual bool isVinValidator() const { return false; } - virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const - { - //std::cerr << "COpRetValidator::validateVout() entered" << std::endl; - - uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid; - uint8_t dummyIsHeirSpendingBegan; - - uint8_t funcId = DecodeHeirEitherOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); - if (funcId == 0) { - message = std::string("invalid opreturn format"); - return false; - } - - uint8_t initialFuncId = DecodeHeirEitherOpRet(m_fundingOpretScript, initialTokenid, dummyTxid, dummyIsHeirSpendingBegan, true); - if (initialFuncId == 0) { - message = std::string("invalid initial tx opreturn format"); - return false; - } - - // validation rules: - if (!isMyFuncId(funcId)) { - message = std::string("invalid funcid in opret"); - return false; - } - - if (typeid(Helper) == typeid(TokenHelper)) { - if (tokenid != initialTokenid) { - message = std::string("invalid tokenid in opret"); - return false; - } - } - - //std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl; - return true; - } - virtual bool validateVin(CTxIn vin, std::vector prevVout, int32_t prevN, std::string& message) const { return true; } - -private: - CScript m_fundingOpretScript; -}; - - -/** - * marker spending prevention validator, - * returns false if for tx with funcid=F vout.1 is being tried to spend - */ -template class CMarkerValidator : CValidatorBase -{ -public: - CMarkerValidator(CCcontract_info* cp) - : CValidatorBase(cp) { } - - virtual bool isVinValidator() const { return true; } // this is vin validator - virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; } - virtual bool validateVin(CTxIn vin, std::vector prevVout, int32_t prevN, std::string& message) const { - - uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid; - uint8_t dummyIsHeirSpendingBegan; - - //std::cerr << "CMarkerValidator::validateVin() prevVout.size()=" << prevVout.size() << " prevN=" << prevN << std::endl; - if (prevVout.size() > 0) { - - // get funcId for prev tx: - uint8_t funcId = DecodeHeirEitherOpRet(prevVout[prevVout.size()-1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); - - //std::cerr << "CMarkerValidator::validateVin() funcId=" << (funcId?funcId:' ') << std::endl; - - if (funcId == 'F' && prevN == 1) { // do not allow to spend 'F' marker's vout - message = std::string("spending marker not allowed"); - return false; - } - } - //std::cerr << "CMarkerValidator::validateVin() exits with true" << std::endl; - return true; - } -}; - -/** - * empty validator always returns true - */ -template class CNullValidator : CValidatorBase -{ -public: - CNullValidator(CCcontract_info* cp) - : CValidatorBase(cp) { } - - virtual bool isVinValidator() const { return false; } - virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; } - virtual bool validateVin(CTxIn vin, std::vector prevVout, int32_t prevN, std::string& message) const { return true; } -}; - - -#endif