From fea2b66581b9a6fbcfed431e91a6c6ee97fb70ea Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sat, 20 Apr 2019 19:29:16 +0800 Subject: [PATCH] add validation for OP_RETURN to payments CC. Enable ccvoutopret for payments fund. --- src/cc/CCinclude.h | 7 +++- src/cc/CCutils.cpp | 53 ++++++++++++++++++++----- src/cc/customcc.cpp | 32 +++++---------- src/cc/payments.cpp | 96 +++++++++++++++++++++++++++++++++++---------- 4 files changed, 135 insertions(+), 53 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 5a515634d..db1ee7475 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -226,8 +226,11 @@ bool priv2addr(char *coinaddr,uint8_t buf33[33],uint8_t priv32[32]); CPubKey buf2pk(uint8_t *buf33); void endiancpy(uint8_t *dest,uint8_t *src,int32_t len); uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout); -CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, const std::vector>* vData = NULL); -CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, const std::vector>* vData = NULL); +CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, std::vector>* vData = NULL); +CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, std::vector>* vData = NULL); +int32_t has_opret(const CTransaction &tx, uint8_t evalcode); +CScript getCCopret(const CScript &scriptPubKey); +bool makeCCopret(CScript &opret, std::vector> &vData); CC *MakeCCcond1(uint8_t evalcode,CPubKey pk); CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2); CC* GetCryptoCondition(CScript const& scriptSig); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index e9acfbe20..b563bd09a 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -58,35 +58,70 @@ CC *MakeCCcond1(uint8_t evalcode,CPubKey pk) return CCNewThreshold(2, {condCC, Sig}); } -CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, const std::vector>* vData) +int32_t has_opret(const CTransaction &tx, uint8_t evalcode) +{ + int i = 0; + for ( auto vout : tx.vout ) + { + if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode ) + return i; + i++; + } + return 0; +} + +CScript getCCopret(const CScript &scriptPubKey) +{ + std::vector> vParams = std::vector>(); + CScript dummy; CScript opret; + if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) ) + { + //opret << E_MARSHAL(ss << vParams[0]); + opret = CScript(vParams[0].begin()+6, vParams[0].end()); + } + //fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vParams.size(), HexStr(vParams[0].begin(),vParams[0].end()).c_str()); + //opret = CScript(vParams[0].begin(), vParams[0].end()); + return opret; +} + +bool makeCCopret(CScript &opret, std::vector> &vData) +{ + if ( opret.empty() ) + return false; + vData.push_back(std::vector(opret.begin(), opret.end())); + return true; +} + +CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, std::vector>* vData) { CTxOut vout; CC *payoutCond = MakeCCcond1(evalcode,pk); vout = CTxOut(nValue,CCPubKey(payoutCond)); if ( vData ) { - std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); + //std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); std::vector vPubKeys = std::vector(); - vPubKeys.push_back(pk); - COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, vtmpData); + //vPubKeys.push_back(pk); + COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, ( * vData)); vout.scriptPubKey << ccp.AsVector() << OP_DROP; } cc_free(payoutCond); return(vout); } -CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, const std::vector>* vData) +CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, std::vector>* vData) { CTxOut vout; CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2); vout = CTxOut(nValue,CCPubKey(payoutCond)); if ( vData ) { - std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); + //std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); std::vector vPubKeys = std::vector(); - vPubKeys.push_back(pk1); - vPubKeys.push_back(pk2); - COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, vtmpData); + // skip pubkeys. These need to maybe be optional and we need some way to get them out that is easy! + //vPubKeys.push_back(pk1); + //vPubKeys.push_back(pk2); + COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, ( * vData)); vout.scriptPubKey << ccp.AsVector() << OP_DROP; } cc_free(payoutCond); diff --git a/src/cc/customcc.cpp b/src/cc/customcc.cpp index 2e174f510..a8b0bf871 100644 --- a/src/cc/customcc.cpp +++ b/src/cc/customcc.cpp @@ -67,38 +67,26 @@ UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) // make op_return payload as normal. CScript opret = custom_opret('1',mypk); std::vector> vData = std::vector>(); - vData.push_back(std::vector(opret.begin(), opret.end())); - // make vout0 with op_return included as payload. - mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData)); - fprintf(stderr, "vout size2.%li\n", mtx.vout.size()); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript()); - return(custom_rawtxresult(result,rawtx,broadcastflag)); + if ( makeCCopret(opret, vData) ) + { + // make vout0 with op_return included as payload. + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData)); + fprintf(stderr, "vout size2.%li\n", mtx.vout.size()); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript()); + return(custom_rawtxresult(result,rawtx,broadcastflag)); + } } return(result); } -bool has_opret(const CTransaction &tx, uint8_t evalcode) -{ - for ( auto vout : tx.vout ) - { - if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode ) - return true; - } - return false; -} - bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { char expectedaddress[64]; CPubKey pk; CScript opret; int32_t numvout; - if ( !has_opret(tx, EVAL_CUSTOM) ) + if ( has_opret(tx, EVAL_CUSTOM) == 0 ) { std::vector> vParams = std::vector>(); - CScript dummy; - if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() == 1 ) - { - opret << E_MARSHAL(ss << vParams[0]); - } + opret = getCCopret(tx.vout[0].scriptPubKey); numvout = 1; } else diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index d83cd0bec..3e4666f47 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -16,6 +16,12 @@ #include "CCPayments.h" /* + +-earlytxid is not an -ac_param, so it doesnt affect the chain magics +extra data after the normal CCvout is whatever data we want and can represent whatever we want +so -ac_script= +in the validation if you see the useearlytxid in the opreturn data or extra data, you use the earlytxid as the txid that specifies the payment + 0) txidopret <- allocation, scriptPubKey, opret 1) create <- locked_blocks, minrelease, list of txidopret @@ -212,6 +218,20 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & allocations.push_back(allocation); //fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation); checkallocations += allocation; + // if we have an op_return to pay to need to check it exists and is paying the correct opret. + if ( !opret.empty() ) + { + if ( !fHasOpret ) + { + fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str()); + return(eval->Invalid("missing opret in payments release")); + } + else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey ) + { + fprintf(stderr, "opret.%s vs opret.%s\n",HexStr(opret.begin(), opret.end()).c_str(), HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin(), tx.vout[tx.vout.size()-1].scriptPubKey.end()).c_str()); + return(eval->Invalid("pays incorrect opret")); + } + } } i++; } @@ -277,14 +297,24 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey); if ( strcmp(destaddr,coinaddr) != 0 ) { - std::vector scriptPubKey,opret; uint256 checktxid; - if ( txin.vout.size() < 2 || DecodePaymentsFundOpRet(txin.vout[txin.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid ) + CScript opret; uint256 checktxid; int32_t opret_ind; + if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) + { + // get op_return from CCvout + opret = getCCopret(txin.vout[0].scriptPubKey); + } + else + { + // get op_return from the op_return + opret = txin.vout[opret_ind].scriptPubKey; + } // else return(eval->Invalid("vin has wrong amount of vouts")); // dont think this is needed? + if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); return(eval->Invalid("vin is not paymentsCC type")); - } //else fprintf(stderr, "vin.%i opret type txid.%s\n", i, txin.GetHash().ToString().c_str()); + } } - // check the chain depth vs locked blcoks requirement. + // check the chain depth vs locked blocks requirement. CBlockIndex* pblockindex = mapBlockIndex[blockhash]; if ( pblockindex->GetHeight() > ht-lockedblocks ) { @@ -340,8 +370,18 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP } if ( iter == 0 ) { - std::vector scriptPubKey,opret; - if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() < 2 || DecodePaymentsFundOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid ) + CScript opret; uint256 checktxid; int32_t opret_ind; + if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 ) + { + // get op_return from CCvout + opret = getCCopret(vintx.vout[0].scriptPubKey); + } + else + { + // get op_return from the op_return + opret = vintx.vout[opret_ind].scriptPubKey; + } + if ( myGetTransaction(txid,tx,hashBlock) == 0 || DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str()); continue; @@ -603,10 +643,16 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) } else { - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); opret = EncodePaymentsFundOpRet(txid); + fprintf(stderr, "opret.%s\n", HexStr(opret.begin(), opret.end()).c_str()); + std::vector> vData = std::vector>(); + if ( makeCCopret(opret, vData) ) + { + mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); + fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vData.size(), HexStr(vData[0].begin(),vData[0].end()).c_str()); + } } - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); if ( params != 0 ) free_json(params); return(payments_rawtxresult(result,rawtx,1)); @@ -630,24 +676,34 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); CPubKey mypk; std::string rawtx; - std::vector scriptPubKey,opret; int32_t allocation,n,retval0,retval1=0; + std::vector scriptPubKey,opret; int32_t n,retval0,retval1=0; int64_t allocation; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); if ( params != 0 && n > 1 && n <= 3 ) { - allocation = juint(jitem(params,0),0); + allocation = (int64_t)jint(jitem(params,0),0); retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0); - if ( n == 3 ) - retval1 = payments_parsehexdata(opret,jitem(params,2),0); - if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE,10) > 0 ) + CScript test = CScript(scriptPubKey.begin(),scriptPubKey.end()); + txnouttype whichType; + if (!::IsStandard(test, whichType)) { - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret)); - if ( params != 0 ) - free_json(params); - return(payments_rawtxresult(result,rawtx,1)); + result.push_back(Pair("result","error")); + result.push_back(Pair("error","scriptPubkey is not valid payment.")); + } + else + { + if ( n == 3 ) + retval1 = payments_parsehexdata(opret,jitem(params,2),0); + if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE*2,10) > 0 ) + { + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret)); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,1)); + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid params or cant find txfee")); } - result.push_back(Pair("result","error")); - result.push_back(Pair("error","invalid params or cant find txfee")); } else { @@ -867,7 +923,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) funds = CCaddress_balance(fundsaddr,1); result.push_back(Pair(fundsaddr,ValueFromAmount(funds))); GetCCaddress(cp,fundsopretaddr,Paymentspk); - fundsopret = CCaddress_balance(fundsopretaddr,1); + fundsopret = CCaddress_balance(fundsopretaddr,1); // Shows balance for ALL payments plans, not just the one asked for! result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret))); result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret))); result.push_back(Pair("result","success"));