diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 2ebba82f7..0dc7f446d 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -188,7 +188,9 @@ void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t * void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr); CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2); +CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk); CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2); +CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk); bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2); void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 0829623e6..2f9a50a93 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -239,23 +239,63 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & // return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); } +// helper funcs: +// extract my vins pubkeys: +bool ExtractVinPubkeys(struct CCcontract_info *cp, CTransaction tx, std::vector &vinPubkeys) { + + bool found = false; + CPubKey pubkey; + + for (int32_t i = 0; i < tx.vin.size(); i++) + { // check for additional contracts which may send tokens to the Tokens contract + if( (*cp->ismyvin)(tx.vin[i].scriptSig) ) + { + + auto findEval = [](CC *cond, struct CCVisitor _) { + bool r = false; //cc_typeId(cond) == CC_Eval && cond->codeLength == 1 && cond->code[0] == EVAL_TOKENS; + + if (cc_typeId(cond) == CC_Secp256k1) { + *(CPubKey*)_.context = buf2pk(cond->publicKey); + //std::cerr << "findEval found pubkey=" << HexStr(*(CPubKey*)_.context) << std::endl; + r = true; + } + // false for a match, true for continue + return r ? 0 : 1; + }; + + CC *cond = GetCryptoCondition(tx.vin[i].scriptSig); + + if (cond) { + CCVisitor visitor = { findEval, (uint8_t*)"", 0, &pubkey }; + bool out = !cc_visit(cond, visitor); + cc_free(cond); + + if (pubkey.IsValid()) { + vinPubkeys.push_back(pubkey); + found = true; + } + } + } + } + return found; +} // this is just for log messages indentation fur debugging recursive calls: thread_local uint32_t tokenValIndentSize = 0; // validates opret for token tx: -bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector &voutPubkeys, std::vector &vopretExtra) { +bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, uint8_t &evalCodeInOpret, std::vector &voutPubkeys, std::vector &vopretExtra) { uint256 tokenidOpret, tokenidOpret2; - uint8_t funcid, evalCode; + uint8_t funcid; // this is just for log messages indentation fur debugging recursive calls: std::string indentStr = std::string().append(tokenValIndentSize, '.'); int32_t n = tx.vout.size(); - if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, tokenidOpret, voutPubkeys, vopretExtra)) == 0) + if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCodeInOpret, tokenidOpret, voutPubkeys, vopretExtra)) == 0) { std::cerr << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl; return(false); @@ -324,20 +364,20 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; - const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); + uint8_t evalCodeInOpret = 0; + const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, evalCodeInOpret, voutPubkeys, vopretExtra); //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (valOpret) { //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned true" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; - if (checkPubkeys) { - // verify that the vout is within EVAL_TOKENS: + if (checkPubkeys) { // verify that the vout is within EVAL_TOKENS: if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { CTxOut testVout; if (voutPubkeys.size() == 1) - testVout = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]); + testVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0]); else // voutPubkeys.size() == 2 - testVout = MakeTokensCC1of2vout(EVAL_HEIR, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]); + testVout = MakeTokensCC1of2vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]); if (tx.vout[v].scriptPubKey == testVout.scriptPubKey) { //std::cerr << indentStr << "IsTokensvout() vout is EVAL_TOKENS, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; @@ -345,9 +385,9 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c } } - // maybe it is change? + // maybe it is token change? for(std::vector::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) { - CTxOut testVout = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it); + CTxOut testVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, *it); if (tx.vout[v].scriptPubKey == testVout.scriptPubKey) { //std::cerr << indentStr << "IsTokensvout() vout is EVAL_TOKENS change, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; @@ -371,7 +411,6 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t { CTransaction vinTx; uint256 hashBlock, id, id2; int32_t flag; int64_t tokenoshis; std::vector tmporigpubkey; int64_t tmpprice; std::vector vinPubkeys, vinPubkeysEmpty; - CPubKey pubkey; int32_t numvins = tx.vin.size(); int32_t numvouts = tx.vout.size(); @@ -380,37 +419,12 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t // this is just for log messages indentation for debugging recursive calls: std::string indentStr = std::string().append(tokenValIndentSize, '.'); + ExtractVinPubkeys(cpTokens, tx, vinPubkeys); + for (int32_t i = 0; iismyvin)(tx.vin[i].scriptSig) /*|| IsVinAllowed(tx.vin[i].scriptSig) != 0*/) { - - // extract my vins pubkeys: - - auto findEval = [](CC *cond, struct CCVisitor _) { - bool r = false; //cc_typeId(cond) == CC_Eval && cond->codeLength == 1 && cond->code[0] == EVAL_TOKENS; - - if (cc_typeId(cond) == CC_Secp256k1) { - *(CPubKey*)_.context = buf2pk(cond->publicKey); - //std::cerr << "findEval found pubkey=" << HexStr(*(CPubKey*)_.context) << std::endl; - r = true; - } - // false for a match, true for continue - return r ? 0 : 1; - }; - - CC *cond = GetCryptoCondition(tx.vin[i].scriptSig); - - if (cond) { - CCVisitor visitor = { findEval, (uint8_t*)"", 0, &pubkey }; - bool out = !cc_visit(cond, visitor); - cc_free(cond); - - if (pubkey.IsValid()) - vinPubkeys.push_back(pubkey); - } - - //std::cerr << indentStr << "TokensExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl; // we are not inside the validation code -- dimxy if ((eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock))) @@ -423,7 +437,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t tokenValIndentSize++; // validate vouts of vintx //std::cerr << indentStr << "TokenExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl; - tokenoshis = IsTokensvout(goDeeper, false/*<--do not have pubkeys for now*/, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeysEmpty); + tokenoshis = IsTokensvout(goDeeper, true, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeys); tokenValIndentSize--; if (tokenoshis != 0) { @@ -488,21 +502,23 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C break; if (j != mtx.vin.size()) continue; + if (GetTransaction(txid, vintx, hashBlock, false) != 0) { Getscriptaddress(destaddr, vintx.vout[vout].scriptPubKey); if (strcmp(destaddr, coinaddr) != 0 && strcmp(destaddr, cp->unspendableCCaddr) != 0 && strcmp(destaddr, cp->unspendableaddr2) != 0) continue; - //fprintf(stderr, "AddTokenCCInputs() check destaddress=%s vout amount=%.8f\n", destaddr, (double)vintx.vout[vout].nValue / COIN); + fprintf(stderr, "AddTokenCCInputs() check destaddress=%s vout amount=%.8f\n", destaddr, (double)vintx.vout[vout].nValue / COIN); - std::vector vinPubkeysEmpty; - if ((nValue = IsTokensvout(true, false/*<-- do not check spending outside EVAL_TOKENS for now */, cp, NULL, vopretExtra, vintx, vout, tokenid, vinPubkeysEmpty)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) + std::vector vinPubkeys; + + if ((nValue = IsTokensvout(true, true/*<--add only checked uxtos */, cp, NULL, vopretExtra, vintx, vout, tokenid, vinPubkeys)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) { if (total != 0 && maxinputs != 0) mtx.vin.push_back(CTxIn(txid, vout, CScript())); nValue = it->second.satoshis; totalinputs += nValue; - //std::cerr << "AddTokenInputs() adding input nValue=" << nValue << std::endl; + std::cerr << "AddTokenInputs() adding input nValue=" << nValue << std::endl; n++; if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 93c82945e..82b74cc11 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -90,6 +90,16 @@ CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) return cond1of2Threshold; } +CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) +{ + std::vector pks; + pks.push_back(CCNewSecp256k1(pk)); + CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); + CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // this is eval token cc + CC *Sig = CCNewThreshold(1, pks); + return CCNewThreshold(3, { condEvalCC, condEvalTokensCC, Sig }); +} + CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) { CTxOut vout; @@ -99,6 +109,15 @@ CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubK return(vout); } +CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) +{ + CTxOut vout; + CC *payoutCond = MakeTokensCCcond1(evalcode, pk); + vout = CTxOut(nValue, CCPubKey(payoutCond)); + cc_free(payoutCond); + return(vout); +} + CC* GetCryptoCondition(CScript const& scriptSig) { auto pc = scriptSig.begin(); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 73d8b49aa..7d1d56006 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -161,7 +161,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction std::cerr << "HeirValidate funcid=" << (char)funcId << " evalcode=" << (int)cpHeir->evalcode << std::endl; //////////////// temp //////////////////////// - return true; + ///return true; switch (funcId) { case 'F':