From 8e8a94404f2d58020637e1a73fa68bca723d6bef Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 7 Jan 2019 23:19:47 +0500 Subject: [PATCH 001/106] Split Asset contract into Tokens and Assets --- src/Makefile.am | 1 + src/cc/CCHeir.h | 25 +- src/cc/CCassets.h | 22 +- src/cc/CCassetsCore.cpp | 401 ++++++----- src/cc/CCassetstx.cpp | 435 ++++++++---- src/cc/CCcustom.cpp | 22 + src/cc/CCinclude.h | 17 +- src/cc/CCtokens.cpp | 487 +++++++++++++ src/cc/CCtokens.h | 76 ++ src/cc/CCtx.cpp | 13 +- src/cc/assets.cpp | 167 +++-- src/cc/eval.h | 3 +- src/cc/heir.cpp | 1426 +++++++++++++++++++++++++++++++++----- src/cc/heir_validate.h | 622 +++++++++++++++++ src/rpc/server.cpp | 15 +- src/rpc/server.h | 9 + src/wallet/rpcwallet.cpp | 441 +++++++++++- 17 files changed, 3591 insertions(+), 591 deletions(-) create mode 100644 src/cc/CCtokens.cpp create mode 100644 src/cc/CCtokens.h create mode 100644 src/cc/heir_validate.h diff --git a/src/Makefile.am b/src/Makefile.am index e6cc5d756..9588cfe44 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -290,6 +290,7 @@ libbitcoin_server_a_SOURCES = \ cc/CCcustom.cpp \ cc/CCtx.cpp \ cc/CCutils.cpp \ + cc/CCtokens.cpp \ cc/assets.cpp \ cc/faucet.cpp \ cc/rewards.cpp \ diff --git a/src/cc/CCHeir.h b/src/cc/CCHeir.h index 214b566c7..18d1f08bb 100644 --- a/src/cc/CCHeir.h +++ b/src/cc/CCHeir.h @@ -18,12 +18,33 @@ #define CC_HEIR_H #include "CCinclude.h" +#include "CCtokens.h" -#define EVAL_HEIR 0xea +//#define EVAL_HEIR 0xea bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); +class CoinHelper; +class TokenHelper; + // CCcustom -UniValue HeirInfo(); + +// this would not link +//template std::string HeirFund(uint64_t txfee,int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); +//template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount); +//template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t nValue); + +std::string HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); +std::string HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); +UniValue HeirClaimCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); +UniValue HeirClaimTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); +UniValue HeirAddCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); +UniValue HeirAddTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); + +UniValue HeirInfo(uint256 fundingtxid); +UniValue HeirList(); +//std::string Heir_MakeBadTx(uint256 fundingtxid, uint8_t funcId, int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTime, uint32_t errMask); + +//bool HeirExactTokenAmounts(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 assetid, const CTransaction &tx); #endif diff --git a/src/cc/CCassets.h b/src/cc/CCassets.h index 5e4441646..5a5ef2c82 100644 --- a/src/cc/CCassets.h +++ b/src/cc/CCassets.h @@ -30,12 +30,12 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx // CCassetsCore //CTxOut MakeAssetsVout(CAmount nValue,CPubKey pk); -CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,std::string name,std::string description); -CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector origpubkey); -bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); -uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey); +//CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,std::string name,std::string description); +//CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector origpubkey); +//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); +//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CTransaction &tx); -int64_t IsAssetvout(int32_t maxAssetExactAmountDepth, struct CCcontract_info *cp, Eval* eval, int64_t &price,std::vector &origpubkey,const CTransaction& tx,int32_t v,uint256 refassetid); +int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid); bool ValidateBidRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); bool ValidateAskRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); @@ -44,18 +44,18 @@ bool SetAskFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValu bool SetSwapFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid); int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid); -bool AssetExactAmounts(int32_t maxDepth, struct CCcontract_info *cp,int64_t &inputs,int32_t starti,int64_t &outputs,Eval* eval,const CTransaction &tx,uint256 assetid); -//bool AssetExactAmounts(bool doValidateTx, struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid, std::vector &ccVinsTxs); +bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid); // CCassetstx int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); -int64_t AddAssetInputs(CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); +int64_t AddAssetInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 assetid, int64_t total, int32_t maxinputs); + UniValue AssetOrders(uint256 tokenid); UniValue AssetInfo(uint256 tokenid); UniValue AssetList(); -std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description); -std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total); -std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode); +//std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description); +//std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total); +//std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode); std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal); std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid); diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 52f1ed28c..52c73d47f 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * + * Copyright © 2014-2018 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * @@ -33,7 +33,7 @@ Yes, this is quite confusing... - In ValudateAssetRemainder the naming convention is nValue is the coin/asset with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or assets, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits. + In ValidateAssetRemainder the naming convention is nValue is the coin/asset with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or assets, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits. We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it. */ @@ -230,38 +230,45 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6 return(true); } +/* use EncodeTokenCreateOpRet instead: CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,std::string name,std::string description) { CScript opret; uint8_t evalcode = EVAL_ASSETS; opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description); return(opret); } +*/ -CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector origpubkey) +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector origpubkey) { - CScript opret; uint8_t evalcode = EVAL_ASSETS; - assetid = revuint256(assetid); - switch ( funcid ) + CScript opret; + uint8_t evalcode = EVAL_ASSETS; + uint8_t funcId = (uint8_t)'t'; + + tokenid = revuint256(tokenid); + switch ( assetFuncId ) { - case 't': case 'x': case 'o': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid); + //case 't': this cannot be here + case 'x': case 'o': + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId); break; case 's': case 'b': case 'S': case 'B': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << price << origpubkey); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId << price << origpubkey); break; case 'E': case 'e': assetid2 = revuint256(assetid2); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << assetid2 << price << origpubkey); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId << assetid2 << price << origpubkey); break; default: - fprintf(stderr,"EncodeOpRet: illegal funcid.%02x\n",funcid); + fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId); opret << OP_RETURN; break; } return(opret); } -bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description) +// it is for compatibility, do not use this for new contracts (use DecodeTokenCreateOpRet) +bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description) { std::vector vopret; uint8_t evalcode,funcid,*script; GetOpReturnData(scriptPubKey, vopret); @@ -274,59 +281,87 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector &or return(0); } -uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey) +uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey) { - std::vector vopret; uint8_t funcid=0,*script,e,f; - GetOpReturnData(scriptPubKey, vopret); + std::vector vopret; + uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyFuncId; + uint256 dummyTokenid; + + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); - memset(&assetid,0,sizeof(assetid)); - memset(&assetid2,0,sizeof(assetid2)); - price = 0; - if ( script != 0 && script[0] == EVAL_ASSETS ) - { - funcid = script[1]; - //fprintf(stderr,"decode.[%c]\n",funcid); - switch ( funcid ) + if (script == 0) { + std::cerr << "DecodeAssetOpRet() script is empty" << std::endl; + return (uint8_t)0; + } + + tokenid = zeroid; + assetid2 = zeroid; + price = 0; + + bool isEof = true; // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! + bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof()); + + if (!result && isEof) { // NOTE: 'result==false' means 'parse error' OR 'not eof state'. Consequently, 'result==false' but 'isEof==true' means just 'parse error' + std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << std::endl; + return (uint8_t)0; + } + + tokenid = revuint256(tokenid); + + std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl; + + if(evalCodeInOpret == EVAL_ASSETS) + { + //fprintf(stderr,"decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId); + switch( assetFuncId ) { - case 'c': return(funcid); - break; - case 't': case 'x': case 'o': - if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid) != 0 ) + /*case 'c': + return(funcid); + break; */ + /*case 't': + if (E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> tokenid; isEof = ss.eof()) || !isEof) + { + assetid = revuint256(assetid); + return(funcid); + } + break; */ + + case 'x': case 'o': + if (isEof) // no data after 'assetFuncId' allowed { - assetid = revuint256(assetid); - return(funcid); + return(assetFuncId); } break; case 's': case 'b': case 'S': case 'B': - if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> price; ss >> origpubkey) != 0 ) + if (E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> dummyTokenid; ss >> dummyFuncId; ss >> price; ss >> origpubkey) != 0) { - assetid = revuint256(assetid); //fprintf(stderr,"got price %llu\n",(long long)price); - return(funcid); + return(assetFuncId); } break; case 'E': case 'e': - if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) + if ( E_UNMARSHAL(vopret,ss >> dummyEvalCode; ss >> dummyFuncId; ss >> dummyTokenid; ss >> dummyFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) { //fprintf(stderr,"got price %llu\n",(long long)price); - assetid = revuint256(assetid); assetid2 = revuint256(assetid2); - return(funcid); + return(assetFuncId); } break; default: - fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n",funcid); - funcid = 0; + fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n", funcId); + funcId = 0; break; } } - return(funcid); + return(funcId); } bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CTransaction &tx) { uint256 assetid,assetid2; - if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 ) + uint8_t evalCode; + if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey) != 0 ) return(true); else return(false); } @@ -334,8 +369,10 @@ bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CT bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx) { uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector origpubkey; CScript script; + uint8_t evalCode; + n = tx.vout.size(); - if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 ) + if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey)) == 0 ) return(false); if ( GetCCaddress(cp,CCaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 ) return(true); @@ -343,76 +380,6 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,co } -// Checks if the vout is a really Asset CC vout -// if maxAssetExactAmountDepth > 0, it also validates the vin transaction itself: -// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx -int64_t IsAssetvout(int32_t maxAssetExactAmountDepth, struct CCcontract_info *cp, Eval* eval, int64_t &price,std::vector &origpubkey,const CTransaction& tx,int32_t v,uint256 refassetid) -{ - uint256 assetid,assetid2; int64_t nValue=0; int32_t n; uint8_t funcid; - - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) // maybe check address too? - { - - if (maxAssetExactAmountDepth > 0) { - //validate all tx - int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0; - std::vector ccVinsTxs; - - //std::cerr << "IsAssetvout() validate=yes" << std::endl; - const bool validateVinTxs = false; - bool isEqualAmounts = AssetExactAmounts(maxAssetExactAmountDepth, cp, myCCVinsAmount, 0, myCCVoutsAmount, eval, tx, refassetid); - - // if ccInputs != ccOutputs and it is not the tokenbase tx means it is possibly fake tx (dimxy): - if (!isEqualAmounts && refassetid != tx.GetHash()) { // checking that this is the true tokenbase tx, by verifying that funcid=c, is done further in this function (dimxy) - std::cerr << "IsAssetvout() detected bad tx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx" << std::endl; - return 0; - } - } - - - n = tx.vout.size(); - if (v >= n - 1) { // just moved this up (dimxy) - std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl; - return(0); - } - nValue = tx.vout[v].nValue; - - // fprintf(stderr,"IsAssetvout() CC vout v.%d of n=%d amount=%.8f\n",v,n,(double)nValue/COIN); - - if ( (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey,assetid,assetid2,price,origpubkey)) == 0 ) - { - fprintf(stderr,"IsAssetvout() null decodeopret v.%d\n",v); - return(0); - } - else if ( funcid == 'c' ) - { - if (refassetid == tx.GetHash() && v == 0) { - std::cerr << "isAssetVout() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " returning nValue=" << nValue << std::endl; - return(nValue); - } - } - else if ( (funcid == 'b' || funcid == 'B') && v == 0 ) // critical! 'b'/'B' vout0 is NOT asset - return(0); - else if ( funcid != 'E' ) - { - if ( assetid == refassetid ) - { - fprintf(stderr,"IsAssetvout() returning %.8f\n",(double)nValue/COIN); - return(nValue); - } - } - else if ( funcid == 'E' ) - { - if ( v < 2 && assetid == refassetid ) - return(nValue); - else if ( v == 2 && assetid2 == refassetid ) - return(nValue); - } - } - //fprintf(stderr,"Isassetvout: normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN); - return(0); -} - int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx) { uint256 hashBlock; char destaddr[64]; @@ -446,16 +413,16 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid) { - CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid; + CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode; CCaddr[0] = origaddr[0] = 0; if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 ) - return(0); + return(0); else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("invalid normal vout0 for buyvin"); else { //fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr); - if ( vinTx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,assetid,assetid2,tmpprice,tmporigpubkey)) != 'b' && funcid != 'B' ) + if ( vinTx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey, evalCode, assetid,assetid2,tmpprice,tmporigpubkey)) != 'b' && funcid != 'B' ) return eval->Invalid("invalid opreturn for buyvin"); else if ( refassetid != assetid ) return eval->Invalid("invalid assetid for buyvin"); @@ -469,88 +436,162 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid) { CTransaction vinTx; int64_t nValue,assetoshis; - fprintf(stderr,"AssetValidateSellvin\n"); + //fprintf(stderr,"AssetValidateSellvin\n"); if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 ) return(0); - if ( (assetoshis= IsAssetvout(1, cp, NULL, tmpprice,tmporigpubkey,vinTx,0,assetid)) == 0 ) + if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey,vinTx,0,assetid)) == 0 ) return eval->Invalid("invalid missing CC vout0 for sellvin"); else return(assetoshis); } -// overload with additional params for deep tx validation (dimxy) -bool AssetExactAmounts(int maxDepth, struct CCcontract_info *cp, int64_t &inputs, int32_t starti, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid) +// validates opret for asset tx: +bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &price, std::vector &origpubkey) { + + uint256 assetidOpret, assetidOpret2; + uint8_t funcid, evalCode; + + // this is just for log messages indentation fur debugging recursive calls: + int32_t n = tx.vout.size(); + + if ((funcid = DecodeAssetOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0) + { + std::cerr << "ValidateAssetOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl; + return(false); + } +/* it is now on token level: + else if (funcid == 'c') + { + if (assetid != zeroid && assetid == tx.GetHash() && v == 0) { + //std::cerr << "ValidateAssetOpret() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl; + return(true); + } + } + else if (funcid == 't') // TODO: check if this new block does not influence IsAssetVout + { + //std::cerr << "ValidateAssetOpret() assetid=" << assetid.GetHex() << " assetIdOpret=" << assetidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; + if (assetid != zeroid && assetid == assetidOpret) { + //std::cerr << "ValidateAssetOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl; + return(true); + } + } */ + // TODO: hope this was unneeded!!! (dimxy) + else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset + return(false); + else if (funcid != 'E') + { + if (assetid != zeroid && assetidOpret == assetid) + { + //std::cerr << "ValidateAssetOpret() returns true for not 'E', funcid=" << (char)funcid << std::endl; + return(true); + } + } + else if (funcid == 'E') // NOTE: not implemented yet! + { + if (v < 2 && assetid != zeroid && assetidOpret == assetid) + return(true); + else if (v == 2 && assetid != zeroid && assetidOpret2 == assetid) + return(true); + } + + //std::cerr << "ValidateAssetOpret() return false funcid=" << (char)funcid << " assetid=" << assetid.GetHex() << " assetIdOpret=" << assetidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; + return false; +} + +// Checks if the vout is a really Asset CC vout +// compareTotals == true, the func also validates the passed transaction itself: +// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx +int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid) { - CTransaction vinTx; uint256 hashBlock,id,id2; int32_t i,flag,numvins,numvouts; int64_t assetoshis; std::vector tmporigpubkey; int64_t tmpprice; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - inputs = outputs = 0; - maxDepth--; + //std::cerr << "IsAssetvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for assetid=" << refassetid.GetHex() << std::endl; - for (i=starti; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //std::cerr << "AssetExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl; - // we are really not inside validation! -- dimxy - if ( (eval && eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0) || (!eval && !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)) ) - { - fprintf(stderr,"AssetExactAmounts() cannot read vintx i.%d starti.%d numvins.%d\n", i,starti,numvins); - return (!eval) ? false : eval->Invalid("always should find vin, but didnt"); + if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here + { + int32_t n = tx.vout.size(); + // just check boundaries: + if (v >= n - 1) { // just moved this up (dimxy) + std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl; + return(0); + } - } // false means 'don't go deeper' -- dimxy - else if ( (assetoshis= IsAssetvout( maxDepth, cp, eval, tmpprice,tmporigpubkey,vinTx,tx.vin[i].prevout.n,assetid)) != 0 ) - { - fprintf(stderr,"AssetExactAmounts() vin%d %llu, ",i,(long long)assetoshis); - inputs += assetoshis; - } - else - { - if ( vinTx.vout[i].scriptPubKey.IsPayToCryptoCondition() != 0 && DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid ) - { - assetoshis = vinTx.vout[i].nValue; - fprintf(stderr,"AssetExactAmounts() vin%d assetoshis=%llu special case, ",i,(long long)assetoshis); - inputs += assetoshis; - } - } - } - } + // moved opret checking to this new reusable func (dimxy): + const bool valOpret = ValidateAssetOpret(tx, v, refassetid, price, origpubkey); + //std::cerr << "IsAssetvout() ValidateAssetOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl; + if (valOpret) { + //std::cerr << "IsAssetvout() ValidateAssetOpret returned true, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl; + return tx.vout[v].nValue; + } + //fprintf(stderr,"IsAssetvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str()); + } + //fprintf(stderr,"IsAssetvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN); + return(0); +} - if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid ) - flag = 1; - else flag = 0; +// sets cc inputs vs cc outputs and ensures they are equal: +bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid) +{ + CTransaction vinTx; uint256 hashBlock, id, id2; int32_t flag; int64_t assetoshis; std::vector tmporigpubkey; int64_t tmpprice; + int32_t numvins = tx.vin.size(); + int32_t numvouts = tx.vout.size(); + inputs = outputs = 0; - for (i=0; iismyvin)(tx.vin[i].scriptSig) || (*cpTokens->ismyvin)(tx.vin[i].scriptSig)) // || IsVinAllowed(tx.vin[i].scriptSig) != 0) + { + //std::cerr << indentStr << "AssetExactAmounts() 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))) + { + std::cerr << "AssetExactAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl; + return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt"); + } + else { + // validate vouts of vintx + //std::cerr << indentStr << "AssetExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl; + assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, vinTx, tx.vin[i].prevout.n, assetid); + if (assetoshis != 0) + { + std::cerr << "AssetExactAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl; + inputs += assetoshis; + } + } + } + } + + // we do not use this flag anymore + //if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid ) + //flag = 1; + //else + //flag = 0; + + for (int32_t i = 0; i ccVinsTxs; - - return AssetExactAmounts(true, cp, inputs, starti, outputs, eval, tx, assetid); -}*/ diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index fbc53406b..cae4b42bb 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -14,6 +14,8 @@ ******************************************************************************/ #include "CCassets.h" +//#include "CCtokens.h" + int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs) { @@ -21,25 +23,31 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - threshold = total/(maxinputs!=0?maxinputs:64); + + threshold = total/(maxinputs!=0?maxinputs:64); // TODO: is maxinputs really not over 64, what if i want to calc total balance? + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; - if ( it->second.satoshis < threshold ) + + if (it->second.satoshis < threshold) continue; + for (j=0; junspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) + if( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) continue; fprintf(stderr,"AddAssetInputs() check destaddress=%s vout amount=%.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN); - if ( (nValue= IsAssetvout(1, cp, NULL, price,origpubkey,vintx,vout,assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) + if( (nValue = IsAssetvout(cp, price, origpubkey, vintx, vout, assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) { if ( total != 0 && maxinputs != 0 ) mtx.vin.push_back(CTxIn(txid,vout,CScript())); @@ -57,12 +65,13 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK return(totalinputs); } + int64_t GetAssetBalance(CPubKey pk,uint256 tokenid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_ASSETS); - return(AddAssetInputs(cp,mtx,pk,tokenid,0,0)); + cp = CCinit(&C,EVAL_TOKENS); + return(AddTokenCCInputs(cp,mtx,pk,tokenid,0,0)); } UniValue AssetInfo(uint256 assetid) @@ -75,11 +84,11 @@ UniValue AssetInfo(uint256 assetid) result.push_back(Pair("error","cant find assetid")); return(result); } - if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 ) + if ( vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 ) { - fprintf(stderr,"assetid isnt assetcreation txid\n"); + fprintf(stderr,"assetid isnt token creation txid\n"); result.push_back(Pair("result","error")); - result.push_back(Pair("error","assetid isnt assetcreation txid")); + result.push_back(Pair("error","assetid isnt token creation txid")); } result.push_back(Pair("result","success")); result.push_back(Pair("tokenid",uint256_str(str,assetid))); @@ -92,15 +101,20 @@ UniValue AssetInfo(uint256 assetid) UniValue AssetList() { - UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; std::vector origpubkey; std::string name,description; char str[65]; - cp = CCinit(&C,EVAL_ASSETS); + UniValue result(UniValue::VARR); + std::vector > addressIndex; + struct CCcontract_info *cp,C; uint256 txid,hashBlock; + CTransaction vintx; std::vector origpubkey; + std::string name,description; char str[65]; + + cp = CCinit(&C,EVAL_TOKENS); SetCCtxids(addressIndex,cp->normaladdr); for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { txid = it->first.txhash; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 ) + if ( vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 ) { result.push_back(uint256_str(str,txid)); } @@ -112,17 +126,33 @@ UniValue AssetList() UniValue AssetOrders(uint256 refassetid) { static uint256 zero; - int64_t price; uint256 txid,hashBlock,assetid,assetid2; std::vector origpubkey; CTransaction vintx; UniValue result(UniValue::VARR); std::vector > unspentOutputs; uint8_t funcid; char numstr[32],funcidstr[16],origaddr[64],assetidstr[65]; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_ASSETS); - SetCCunspents(unspentOutputs,(char *)cp->unspendableCCaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { + UniValue result(UniValue::VARR); + std::vector > unspentOutputsTokens, unspentOutputsAssets; + + struct CCcontract_info *cpTokens, tokensC; + struct CCcontract_info *cpAssets, assetsC; + + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + cpAssets = CCinit(&assetsC, EVAL_ASSETS); + + auto addOrders = [&](struct CCcontract_info *cp, std::vector >::const_iterator it) + { + uint256 txid, hashBlock, assetid, assetid2; + int64_t price; + std::vector origpubkey; + CTransaction vintx; + uint8_t funcid, evalCode; + char numstr[32], funcidstr[16], origaddr[64], assetidstr[65]; + txid = it->first.txhash; - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + //std::cerr << "addOrders txid" << txid.GetHex() << std::endl; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( vintx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,assetid,assetid2,price,origpubkey)) != 0 ) + funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey); + //std::cerr << "addOrders vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << std::endl; + if (vintx.vout.size() > 0 && (funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0) { - if ( refassetid != zero && assetid != refassetid ) + if (refassetid != zero && assetid != refassetid) { //int32_t z; //for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&txid)[z]); @@ -131,11 +161,13 @@ UniValue AssetOrders(uint256 refassetid) //fprintf(stderr," assetid\n"); //for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&refassetid)[z]); //fprintf(stderr," refassetid\n"); - continue; + return; } - if ( vintx.vout[it->first.index].nValue == 0 ) - continue; + if (vintx.vout[it->first.index].nValue == 0) + return; + UniValue item(UniValue::VOBJ); + funcidstr[0] = funcid; funcidstr[1] = 0; item.push_back(Pair("funcid", funcidstr)); @@ -157,8 +189,8 @@ UniValue AssetOrders(uint256 refassetid) } if ( origpubkey.size() == 33 ) { - GetCCaddress(cp,origaddr,pubkey2pk(origpubkey)); - item.push_back(Pair("origaddress",origaddr)); + GetCCaddress(cp, origaddr, pubkey2pk(origpubkey)); // TODO: what is this? is it asset or token?? + item.push_back(Pair("origaddress", origaddr)); } if ( assetid != zeroid ) item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid))); @@ -184,11 +216,27 @@ UniValue AssetOrders(uint256 refassetid) //fprintf(stderr,"func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN); } } - } + }; + + + SetCCunspents(unspentOutputsTokens, (char *)cpTokens->unspendableCCaddr); + SetCCunspents(unspentOutputsAssets, (char *)cpAssets->unspendableCCaddr); + + for (std::vector >::const_iterator itTokens = unspentOutputsTokens.begin(); + itTokens != unspentOutputsTokens.end(); + itTokens++) + addOrders(cpTokens, itTokens); + + for (std::vector >::const_iterator itAssets = unspentOutputsAssets.begin(); + itAssets != unspentOutputsAssets.end(); + itAssets++) + addOrders(cpAssets, itAssets); + return(result); } -std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description) +// not used (use TokenCreate instead) +/* std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; struct CCcontract_info *cp,C; @@ -213,9 +261,10 @@ std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std:: return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetCreateOpRet('c',Mypubkey(),name,description))); } return(""); -} - -std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total) +} */ + +// not used (use TokenTransfer instead) +/* std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; uint64_t mask; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C; @@ -230,11 +279,11 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector des mypk = pubkey2pk(Mypubkey()); if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { - /*n = outputs.size(); - if ( n == amounts.size() ) - { - for (i=0; i 0 ) { @@ -254,9 +303,10 @@ std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector des //} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size()); } return(""); -} +} */ -std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode) +// deprecated +/* std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; int64_t CCchange=0,inputs=0; struct CCcontract_info *cp,C; @@ -281,76 +331,106 @@ std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector dest } else fprintf(stderr,"not enough CC asset inputs for %.8f\n",(double)total/COIN); } return(""); -} +} */ -std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal) +// rpc tokenbid implementation, locks 'bidamount' coins for the 'pricetotal' of tokens +std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, int64_t pricetotal) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk; struct CCcontract_info *cp,C; uint256 hashBlock; CTransaction vintx; std::vector origpubkey; std::string name,description; - if ( bidamount < 0 || pricetotal < 0 ) + CPubKey mypk; + struct CCcontract_info *cpAssets, C; + uint256 hashBlock; + CTransaction vintx; + std::vector origpubkey; + std::string name,description; + int64_t inputs; + + std::cerr << "CreateBuyOffer() bidamount=" << bidamount << " numtokens(pricetotal)=" << pricetotal << std::endl; + + if (bidamount < 0 || pricetotal < 0) { - fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n",(long long)bidamount,(long long)pricetotal); + fprintf(stderr,"negative bidamount %lld, pricetotal %lld\n", (long long)bidamount, (long long)pricetotal); return(""); } - if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 ) + if (GetTransaction(assetid, vintx, hashBlock, false) == 0) { fprintf(stderr,"cant find assetid\n"); return(""); } - if ( vintx.vout.size() > 0 && DecodeAssetCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 ) + if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, origpubkey, name, description) == 0) { fprintf(stderr,"assetid isnt assetcreation txid\n"); return(""); } - cp = CCinit(&C,EVAL_ASSETS); - if ( txfee == 0 ) + + cpAssets = CCinit(&C,EVAL_ASSETS); // NOTE: assets here! + if (txfee == 0) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,bidamount+txfee,64) > 0 ) + + if ((inputs = AddNormalinputs(mtx, mypk, bidamount+txfee, 64)) > 0) { - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount,GetUnspendable(cp,0))); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('b',assetid,zeroid,pricetotal,Mypubkey()))); + std::cerr << "CreateBuyOffer() inputs=" << inputs << std::endl; + if (inputs < bidamount+txfee) { + std::cerr << "CreateBuyOffer(): insufficient coins to make buy offer" << std::endl; + CCerror = strprintf("insufficient coins to make buy offer"); + return (""); + } + + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, GetUnspendable(cpAssets,0))); + return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, Mypubkey()))); } + CCerror = strprintf("no coins found to make buy offer"); return(""); } +// rpc tokenask implementation, locks 'askamount' tokens for the 'pricetotal' std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C; + CPubKey mypk; + uint64_t mask; + int64_t inputs, CCchange; + CScript opret; + struct CCcontract_info *cp,C; //std::cerr << "CreateSell() askamount=" << askamount << " pricetotal=" << pricetotal << std::endl; - if ( askamount < 0 || pricetotal < 0 ) - { + if (askamount < 0 || pricetotal < 0) { fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount); return(""); } - cp = CCinit(&C,EVAL_ASSETS); + + cp = CCinit(&C, EVAL_TOKENS); // NOTE: tokens is here + if ( txfee == 0 ) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); - if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 ) + if ((inputs = AddTokenCCInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0) { if (inputs < askamount) { - //askamount = inputs; + //was: askamount = inputs; std::cerr << "CreateSell(): insufficient tokens for ask" << std::endl; + CCerror = strprintf("insufficient tokens for ask"); return (""); } - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0))); - if ( inputs > askamount ) + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,askamount, GetUnspendable(cp,0))); + if (inputs > askamount) CCchange = (inputs - askamount); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); - opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey()); + if (CCchange != 0) + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); + + opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, Mypubkey()); return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret)); } else { - fprintf(stderr, "need some assets to place ask\n"); + fprintf(stderr, "need some tokens to place ask\n"); } } else { // dimxy added 'else', because it was misleading message before @@ -363,34 +443,48 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C; + + ////////////////////////////////////////// fprintf(stderr,"asset swaps disabled\n"); return(""); + ////////////////////////////////////////// + if ( askamount < 0 || pricetotal < 0 ) { fprintf(stderr,"negative askamount %lld, askamount %lld\n",(long long)pricetotal,(long long)askamount); return(""); } - cp = CCinit(&C,EVAL_ASSETS); + cp = CCinit(&C, EVAL_ASSETS); + if ( txfee == 0 ) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); - if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,askamount,60)) > 0 ) + if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0) { - if ( inputs < askamount ) - askamount = inputs; - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,GetUnspendable(cp,0))); - if ( inputs > askamount ) + if (inputs < askamount) { + //was: askamount = inputs; + std::cerr << "CreateSwap(): insufficient tokens for ask" << std::endl; + CCerror = strprintf("insufficient tokens for ask"); + return (""); + } + + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, GetUnspendable(cp, 0))); + + if (inputs > askamount) CCchange = (inputs - askamount); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); - if ( assetid2 == zeroid ) - opret = EncodeAssetOpRet('s',assetid,zeroid,pricetotal,Mypubkey()); + if (CCchange != 0) + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); + + if (assetid2 == zeroid) + opret = EncodeAssetOpRet('s', assetid, zeroid, pricetotal, Mypubkey()); else { - opret = EncodeAssetOpRet('e',assetid,assetid2,pricetotal,Mypubkey()); + opret = EncodeAssetOpRet('e', assetid, assetid2, pricetotal, Mypubkey()); } return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret)); } @@ -405,146 +499,213 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a return(""); } +// unlocks coins std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t bidamount; CPubKey mypk; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_ASSETS); + CTransaction vintx; + uint64_t mask; + uint256 hashBlock; + int64_t bidamount; + CPubKey mypk; + struct CCcontract_info *cp,C; + + cp = CCinit(&C, EVAL_ASSETS); + if ( txfee == 0 ) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); - if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 ) + if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0) { bidamount = vintx.vout[0].nValue; - mtx.vin.push_back(CTxIn(bidtxid,0,CScript())); + mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('o',assetid,zeroid,0,Mypubkey()))); + return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, Mypubkey()))); } } return(""); } +//unlocks tokens std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_ASSETS); + CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; + struct CCcontract_info *cp,C; + + cp = CCinit(&C, EVAL_TOKENS); + if ( txfee == 0 ) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); - if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 ) + if (GetTransaction(asktxid, vintx, hashBlock, false) != 0) { askamount = vintx.vout[0].nValue; - mtx.vin.push_back(CTxIn(asktxid,0,CScript())); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,askamount,mypk)); - return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('x',assetid,zeroid,0,Mypubkey()))); + mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); + return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, Mypubkey()))); } } return(""); } +//send tokens, receive coins: std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction vintx; uint256 hashBlock; CPubKey mypk; std::vector origpubkey; int32_t bidvout=0; uint64_t mask; int64_t origprice,bidamount,paid_amount,remaining_required,inputs,CCchange=0; struct CCcontract_info *cp,C; - if ( fillamount < 0 ) + CTransaction vintx; + uint256 hashBlock; + CPubKey mypk; + std::vector origpubkey; + int32_t bidvout=0; + uint64_t mask; + int64_t origprice, bidamount, paid_amount, remaining_required, inputs, CCchange=0; + struct CCcontract_info *cp,C; + + if (fillamount < 0) { - fprintf(stderr,"negative fillamount %lld\n",(long long)fillamount); + fprintf(stderr,"negative fillamount %lld\n", (long long)fillamount); return(""); } - cp = CCinit(&C,EVAL_ASSETS); - if ( txfee == 0 ) + cp = CCinit(&C, EVAL_TOKENS); + + if ( txfee == 0 ) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); - if ( GetTransaction(bidtxid,vintx,hashBlock,false) != 0 ) + if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0) { bidamount = vintx.vout[bidvout].nValue; - SetAssetOrigpubkey(origpubkey,origprice,vintx); - mtx.vin.push_back(CTxIn(bidtxid,bidvout,CScript())); - if ( (inputs= AddAssetInputs(cp,mtx,mypk,assetid,fillamount,60)) > 0 ) + SetAssetOrigpubkey(origpubkey, origprice, vintx); + + mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); + + if ((inputs = AddTokenCCInputs(cp, mtx, mypk, assetid, fillamount, 60)) > 0) { - if ( inputs < fillamount ) - fillamount = inputs; - SetBidFillamounts(paid_amount,remaining_required,bidamount,fillamount,origprice); - if ( inputs > fillamount ) + if (inputs < fillamount) { + std::cerr << "FillBuyOffer(): insufficient tokens to fill buy offer" << std::endl; + CCerror = strprintf("insufficient tokens to fill buy offer"); + return (""); + } + + SetBidFillamounts(paid_amount, remaining_required, bidamount, fillamount, origprice); + + if (inputs > fillamount) CCchange = (inputs - fillamount); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,bidamount - paid_amount,GetUnspendable(cp,0))); + + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, bidamount - paid_amount, GetUnspendable(cp,0))); // tokens mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,fillamount,pubkey2pk(origpubkey))); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); - fprintf(stderr,"remaining %llu -> origpubkey\n",(long long)remaining_required); - return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet('B',assetid,zeroid,remaining_required,origpubkey))); + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, fillamount, pubkey2pk(origpubkey))); // coins + + if (CCchange != 0) + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins + + fprintf(stderr,"remaining %llu -> origpubkey\n", (long long)remaining_required); + + return(FinalizeCCTx(mask,cp,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, origpubkey))); } else return("dont have any assets to fill bid\n"); } } return("no normal coins left"); } + +// send coins, receive tokens std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction vintx,filltx; uint256 hashBlock; CPubKey mypk; std::vector origpubkey; double dprice; uint64_t mask; int32_t askvout=0; int64_t received_assetoshis,total_nValue,orig_assetoshis,paid_nValue,remaining_nValue,inputs,CCchange=0; struct CCcontract_info *cp,C; - if ( fillunits < 0 ) + CTransaction vintx,filltx; + uint256 hashBlock; + CPubKey mypk; + std::vector origpubkey; + double dprice; + uint64_t mask; + int32_t askvout=0; + int64_t received_assetoshis, total_nValue, orig_assetoshis, paid_nValue, remaining_nValue, inputs, CCchange=0; + struct CCcontract_info *cpTokens, tokensC; + struct CCcontract_info *cpAssets, assetsC; + + if (fillunits < 0) { CCerror = strprintf("negative fillunits %lld\n",(long long)fillunits); fprintf(stderr,"%s\n",CCerror.c_str()); return(""); } - if ( assetid2 != zeroid ) + if (assetid2 != zeroid) { CCerror = "asset swaps disabled"; fprintf(stderr,"%s\n",CCerror.c_str()); return(""); } - cp = CCinit(&C,EVAL_ASSETS); - if ( txfee == 0 ) + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + cpAssets = CCinit(&assetsC, EVAL_ASSETS); + + if (txfee == 0) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + if (AddNormalinputs(mtx,mypk,txfee,3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); - if ( GetTransaction(asktxid,vintx,hashBlock,false) != 0 ) + if (GetTransaction(asktxid, vintx, hashBlock, false) != 0) { orig_assetoshis = vintx.vout[askvout].nValue; - SetAssetOrigpubkey(origpubkey,total_nValue,vintx); + SetAssetOrigpubkey(origpubkey, total_nValue, vintx); dprice = (double)total_nValue / orig_assetoshis; paid_nValue = dprice * fillunits; - mtx.vin.push_back(CTxIn(asktxid,askvout,CScript())); - if ( assetid2 != zeroid ) - inputs = AddAssetInputs(cp,mtx,mypk,assetid2,paid_nValue,60); + + mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx! + + if (assetid2 != zeroid) + inputs = AddAssetInputs(cpTokens, mtx, mypk, assetid2, paid_nValue, 60); else { - inputs = AddNormalinputs(mtx,mypk,paid_nValue,60); + inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60); mask = ~((1LL << mtx.vin.size()) - 1); } - if ( inputs > 0 ) + if (inputs > 0) { - if ( inputs < paid_nValue ) - paid_nValue = inputs; - if ( assetid2 != zeroid ) - SetSwapFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue); - else SetAskFillamounts(received_assetoshis,remaining_nValue,orig_assetoshis,paid_nValue,total_nValue); - if ( assetid2 != zeroid && inputs > paid_nValue ) + if (inputs < paid_nValue) { + std::cerr << "FillSell(): insufficient coins to fill sell" << std::endl; + CCerror = strprintf("insufficient coins to fill sell"); + return (""); + } + + if (assetid2 != zeroid) + SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); + else + SetAskFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); + + if (assetid2 != zeroid && inputs > paid_nValue) CCchange = (inputs - paid_nValue); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,orig_assetoshis - received_assetoshis,GetUnspendable(cp,0))); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,received_assetoshis,mypk)); - if ( assetid2 != zeroid ) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,paid_nValue,origpubkey)); - else mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG)); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); - return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet(assetid2!=zeroid?'E':'S',assetid,assetid2,remaining_nValue,origpubkey))); + + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // coins + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); // tokens + + if (assetid2 != zeroid) + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); // tokens (not implemented correctly) + else + mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); // coins + + if (CCchange != 0) + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins + + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, origpubkey))); } else { CCerror = strprintf("filltx not enough utxos"); fprintf(stderr,"%s\n", CCerror.c_str()); diff --git a/src/cc/CCcustom.cpp b/src/cc/CCcustom.cpp index 7fdd1b920..918ceb24a 100644 --- a/src/cc/CCcustom.cpp +++ b/src/cc/CCcustom.cpp @@ -30,6 +30,7 @@ #include "CCMarmara.h" #include "CCPayments.h" #include "CCGateways.h" +#include "CCtokens.h" /* CCcustom has most of the functions that need to be extended to create a new CC contract. @@ -222,6 +223,18 @@ uint8_t GatewaysCCpriv[32] = { 0xf7, 0x4b, 0x5b, 0xa2, 0x7a, 0x5e, 0x9c, 0xda, 0 #undef FUNCNAME #undef EVALCODE +// Tokens +#define FUNCNAME IsTokensInput +#define EVALCODE EVAL_TOKENS +const char *TokensCCaddr = "RAMvUfoyURBRxAdVeTMHxn3giJZCFWeha2"; +const char *TokensNormaladdr = "RCNgAngYAdrfzujYyPgfbjCGNVQZzCgTad"; +char TokensCChexstr[67] = { "03e6191c70c9c9a28f9fd87089b9488d0e6c02fb629df64979c9cdb6b2b4a68d95" }; +uint8_t TokensCCpriv[32] = { 0x1d, 0x0d, 0x0d, 0xce, 0x2d, 0xd2, 0xe1, 0x9d, 0xf5, 0xb6, 0x26, 0xd5, 0xad, 0xa0, 0xf0, 0x0a, 0xdd, 0x7a, 0x72, 0x7d, 0x17, 0x35, 0xb5, 0xe3, 0x2c, 0x6c, 0xa9, 0xa2, 0x03, 0x16, 0x4b, 0xcf }; +#include "CCcustom.inc" +#undef FUNCNAME +#undef EVALCODE + + struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) { cp->evalcode = evalcode; @@ -347,6 +360,15 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) cp->validate = GatewaysValidate; cp->ismyvin = IsGatewaysInput; break; + + case EVAL_TOKENS: + strcpy(cp->unspendableCCaddr, TokensCCaddr); + strcpy(cp->normaladdr, TokensNormaladdr); + strcpy(cp->CChexstr, TokensCChexstr); + memcpy(cp->CCpriv, TokensCCpriv, 32); + cp->validate = TokensValidate; + cp->ismyvin = IsTokensInput; + break; } return(cp); } diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 40028ee5c..56c4b27d5 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -133,13 +133,22 @@ int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char * uint8_t DecodeOraclesCreateOpRet(const CScript &scriptPubKey,std::string &name,std::string &description,std::string &format); uint256 OracleMerkle(int32_t height,uint256 reforacletxid,char *format,std::vectorpublishers); uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk); -int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); + +//int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); +int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); + bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); -bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); -uint8_t DecodeAssetOpRet(const CScript &scriptPubKey,uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey); +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector origpubkey); +bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); +uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); +uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); +uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &vopretExtra); + +//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey); uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data); int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen); -CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector origpubkey); + + // CCcustom CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp new file mode 100644 index 000000000..c85297ddb --- /dev/null +++ b/src/cc/CCtokens.cpp @@ -0,0 +1,487 @@ +/****************************************************************************** + * Copyright © 2014-2018 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. * + * * + ******************************************************************************/ + +#include "CCtokens.h" + +/* TODO: correct this: +----------------------------- + The SetTokenFillamounts() and ValidateTokenRemainder() work in tandem to calculate the vouts for a fill and to validate the vouts, respectively. + + This pair of functions are critical to make sure the trading is correct and is the trickiest part of the tokens contract. + + //vin.0: normal input + //vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] + //vin.2+: valid CC output satisfies buyoffer (*tx.vin[2])->nValue + //vout.0: remaining amount of bid to unspendable + //vout.1: vin.1 value to signer of vin.2 + //vout.2: vin.2 tokenoshis to original pubkey + //vout.3: CC output for tokenoshis change (if any) + //vout.4: normal output for change (if any) + //vout.n-1: opreturn [EVAL_ASSETS] ['B'] [tokenid] [remaining token required] [origpubkey] + ValidateTokenRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits); + + Yes, this is quite confusing... + + In ValudateTokenRemainder the naming convention is nValue is the coin/token with the offer on the books and "units" is what it is being paid in. The high level check is to make sure we didnt lose any coins or tokens, the harder to validate is the actual price paid as the "orderbook" is in terms of the combined nValue for the combined totalunits. + + We assume that the effective unit cost in the orderbook is valid and that that amount was paid and also that any remainder will be close enough in effective unit cost to not matter. At the edge cases, this will probably be not true and maybe some orders wont be practically fillable when reduced to fractional state. However, the original pubkey that created the offer can always reclaim it. + ------------------------------ +*/ + + +// NOTE: this inital tx won't be used by other contract +// for tokens to be used there should be at least one 't' tx with other contract's custom opret +CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector origpubkey,std::string name,std::string description) +{ + CScript opret; uint8_t evalcode = EVAL_TOKENS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << origpubkey << name << description); + return(opret); +} + +// this is for other contracts which use tokens and build customized extra payloads to token's opret: +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector payload) +{ + CScript opret; + //uint8_t evalcode = EVAL_TOKENS; + tokenid = revuint256(tokenid); + //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; + + opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); + return(opret); +} + +uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description) +{ + std::vector vopret; uint8_t dummyEvalcode, funcid, *script; + + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( script != 0 && vopret.size() > 2 && script[0] == EVAL_TOKENS && script[1] == 'c' ) + { + if ( E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description) != 0 ) + return(funcid); + } + return (uint8_t)0; +} + +uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &vopretExtra) +{ + std::vector vopret, extra, dummyPubkey; + uint8_t funcid=0, *script, e, dummyFuncId; + std::string dummyName; std::string dummyDescription; + + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + tokenid = zeroid; + + if (script != 0 /*enable all evals: && script[0] == EVAL_TOKENS*/) + { + bool isEof = true; + evalCode = script[0]; + funcid = script[1]; + //fprintf(stderr,"decode.[%c]\n",funcid); + switch ( funcid ) + { + case 'c': + return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription); + //break; + case 't': + //not used yet: case 'l': + if (E_UNMARSHAL(vopret, ss >> e; ss >> dummyFuncId; ss >> tokenid; isEof = ss.eof(); vopretExtra = std::vector(ss.begin(), ss.end())) || !isEof) + { + tokenid = revuint256(tokenid); + return(funcid); + } + std::cerr << "DecodeTokenOpRet() isEof=" << isEof << std::endl; + fprintf(stderr, "DecodeTokenOpRet() bad opret format\n"); // this may be just check, no error logging + return (uint8_t)0; + + default: + fprintf(stderr, "DecodeTokenOpRet() illegal funcid.%02x\n", funcid); + return (uint8_t)0; + } + } + return (uint8_t)0; +} + + + +// tx validation +bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn) +{ + static uint256 zero; + CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2; + int32_t i, starti, numvins, numvouts, preventCCvins, preventCCvouts; + int64_t remaining_price, nValue, tokenoshis, outputs, inputs, tmpprice, totalunits, ignore; std::vector origpubkey, tmporigpubkey, ignorepubkey; + uint8_t funcid, evalCodeInOpret; + char destaddr[64], origaddr[64], CCaddr[64]; + + numvins = tx.vin.size(); + numvouts = tx.vout.size(); + outputs = inputs = 0; + preventCCvins = preventCCvouts = -1; + + if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, origpubkey)) == 0) + return eval->Invalid("TokenValidate: invalid opreturn payload"); + + fprintf(stderr, "TokensValidate (%c)\n", funcid); + + if (eval->GetTxUnconfirmed(tokenid, createTx, hashBlock) == 0) + return eval->Invalid("cant find token create txid"); + else if (IsCCInput(tx.vin[0].scriptSig) != 0) + return eval->Invalid("illegal token vin0"); // why? (dimxy) + else if (numvouts < 1) + return eval->Invalid("no vouts"); + else if (funcid != 'c') + { + if (tokenid == zeroid) + return eval->Invalid("illegal tokenid"); + else if (!TokensExactAmounts(true, cp, inputs, outputs, eval, tx, tokenid)) { + if (!eval->Valid()) + return false; //TokenExactAmounts must call eval->Invalid()! + else + return eval->Invalid("tokens cc inputs != cc outputs"); + } + } + + // init for forwarding validation call + struct CCcontract_info *cpOther = NULL, C; + if (evalCodeInOpret != EVAL_TOKENS) + cpOther = CCinit(&C, evalCodeInOpret); + + switch (funcid) + { + case 'c': // create wont be called to be verified as it has no CC inputs + //vin.0: normal input + //vout.0: issuance tokenoshis to CC + //vout.1: normal output for change (if any) + //vout.n-1: opreturn EVAL_TOKENS 'c' + if (evalCodeInOpret != EVAL_TOKENS) + return eval->Invalid("unexpected TokenValidate for createtoken"); + else + return true; + + case 't': // transfer + //vin.0: normal input + //vin.1 .. vin.n-1: valid CC outputs + //vout.0 to n-2: tokenoshis output to CC + //vout.n-2: normal output for change (if any) + //vout.n-1: opreturn 't' tokenid + if (inputs == 0) + return eval->Invalid("no token inputs for transfer"); + + fprintf(stderr, "token transfer preliminarily validated %.8f -> %.8f (%d %d)\n", (double)inputs / COIN, (double)outputs / COIN, preventCCvins, preventCCvouts); + break; // breaking to other contract validation... + + default: + fprintf(stderr, "illegal tokens funcid.(%c)\n", funcid); + return eval->Invalid("unexpected token funcid"); + } + + // forward validation if evalcode in opret is not EVAL_TOKENS + if (cpOther) + return cpOther->validate(cpOther, eval, tx, nIn); + else + return eval->Invalid("unsupported evalcode in opret"); + + // what does this do? + // return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); +} + + + +// 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 &vopretExtra) { + + uint256 tokenidOpret, tokenidOpret2; + uint8_t funcid, evalCode; + + // 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, vopretExtra)) == 0) + { + std::cerr << indentStr << "ValidateTokenOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl; + return(false); + } + else if (funcid == 'c') + { + if (tokenid != zeroid && tokenid == tx.GetHash() && v == 0) { + //std::cerr << indentStr << "ValidateTokenOpret() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl; + return(true); + } + } + else if (funcid == 't') + { + //std::cerr << indentStr << "ValidateTokenOpret() tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; + if (tokenid != zeroid && tokenid == tokenidOpret) { + //std::cerr << indentStr << "ValidateTokenOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl; + return(true); + } + } + //std::cerr << indentStr << "ValidateTokenOpret() return false funcid=" << (char)funcid << " tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; + return false; +} + + +// Checks if the vout is a really Tokens CC vout +// compareTotals == true, the func also validates the passed transaction itself: +// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx +int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, std::vector &vopretExtra, const CTransaction& tx, int32_t v, uint256 reftokenid) +{ + + // this is just for log messages indentation fur debugging recursive calls: + std::string indentStr = std::string().append(tokenValIndentSize, '.'); + //std::cerr << indentStr << "IsTokensvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for tokenid=" << reftokenid.GetHex() << std::endl; + + //TODO: validate cc vouts are EVAL_TOKENS! + if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here + { + int32_t n = tx.vout.size(); + // just check boundaries: + if (v >= n - 1) { // just moved this up (dimxy) + std::cerr << indentStr << "isTokensvout() internal err: (v >= n - 1), returning 0" << std::endl; + return(0); + } + + if (compareTotals) { + //std::cerr << indentStr << "IsTokensvout() maxTokenExactAmountDepth=" << maxTokenExactAmountDepth << std::endl; + //validate all tx + int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0; + + tokenValIndentSize++; + // false --> because we already at the 1-st level ancestor tx and do not need to dereference ancestors of next levels + bool isEqual = TokensExactAmounts(false, cp, myCCVinsAmount, myCCVoutsAmount, eval, tx, reftokenid); + tokenValIndentSize--; + + if (!isEqual) { + // if ccInputs != ccOutputs and it is not the tokenbase tx + // this means it is possibly a fake tx (dimxy): + if (reftokenid != tx.GetHash()) { // checking that this is the true tokenbase tx, by verifying that funcid=c, is done further in this function (dimxy) + std::cerr << indentStr << "IsTokensvout() warning: for the verified tx detected a bad vintx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx, skipping the verified tx" << std::endl; + return 0; + } + } + } + + // moved opret checking to this new reusable func (dimxy): + const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, 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, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + return tx.vout[v].nValue; + } + + //std::cerr << indentStr; fprintf(stderr,"IsTokensvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str()); + } + //std::cerr << indentStr; fprintf(stderr,"IsTokensvout() normal output v.%d %.8f\n",v,(double)tx.vout[v].nValue/COIN); + return(0); +} + +// compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs) +bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid) +{ + CTransaction vinTx; uint256 hashBlock, id, id2; int32_t flag; int64_t tokenoshis; std::vector tmporigpubkey; int64_t tmpprice; + int32_t numvins = tx.vin.size(); + int32_t numvouts = tx.vout.size(); + inputs = outputs = 0; + + // this is just for log messages indentation for debugging recursive calls: + std::string indentStr = std::string().append(tokenValIndentSize, '.'); + + for (int32_t i = 0; iismyvin)(tx.vin[i].scriptSig) /*|| IsVinAllowed(tx.vin[i].scriptSig) != 0*/) + { + //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))) + { + std::cerr << indentStr << "TokensExactAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl; + return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt"); + + } + else { + 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(compareTotals, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid); + tokenValIndentSize--; + if (tokenoshis != 0) + { + std::cerr << indentStr << "TokensExactAmounts() vin i=" << i << " tokenoshis=" << tokenoshis << std::endl; + inputs += tokenoshis; + } + } + } + } + + + for (int32_t i = 0; iInvalid() here! + } + else + return true; +} + +// add inputs from token cc addr +int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs) +{ + char coinaddr[64], destaddr[64]; + int64_t threshold, nValue, price, totalinputs = 0; + uint256 txid, hashBlock; + std::vector vopretExtra; + CTransaction vintx; + int32_t j, vout, n = 0; + std::vector > unspentOutputs; + + GetCCaddress(cp, coinaddr, pk); + SetCCunspents(unspentOutputs, coinaddr); + + threshold = total / (maxinputs != 0 ? maxinputs : 64); // TODO: is maxinputs really could not be over 64? what if i want to calc total balance? + + for (std::vector >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + if (it->second.satoshis < threshold) + continue; + for (j = 0; junspendableCCaddr) != 0 && strcmp(destaddr, cp->unspendableaddr2) != 0) + continue; + fprintf(stderr, "AddTokenCCInputs() check destaddress=%s vout amount=%.8f\n", destaddr, (double)vintx.vout[vout].nValue / COIN); + if ((nValue = IsTokensvout(true, cp, NULL, vopretExtra, vintx, vout, tokenid)) > 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; + n++; + if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) + break; + } + } + } + + //std::cerr << "AddTokenInputs() found totalinputs=" << totalinputs << std::endl; + return(totalinputs); +} + + +std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; struct CCcontract_info *cp, C; + if (assetsupply < 0) + { + fprintf(stderr, "negative assetsupply %lld\n", (long long)assetsupply); + return(""); + } + + cp = CCinit(&C, EVAL_TOKENS); + if (name.size() > 32 || description.size() > 4096) + { + fprintf(stderr, "name.%d or description.%d is too big\n", (int32_t)name.size(), (int32_t)description.size()); + return(""); + } + if (txfee == 0) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + + if (AddNormalinputs(mtx, mypk, assetsupply + 2 * txfee, 64) > 0) + { + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, assetsupply, mypk)); + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(cp->CChexstr) << OP_CHECKSIG)); + return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), name, description))); + } + return(""); +} + + +std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey mypk; uint64_t mask; int64_t CCchange = 0, inputs = 0; struct CCcontract_info *cp, C; + std::vector emptyExtraOpret; + + if (total < 0) + { + fprintf(stderr, "negative total %lld\n", (long long)total); + return(""); + } + cp = CCinit(&C, EVAL_TOKENS); + if (txfee == 0) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) + { + //n = outputs.size(); + //if ( n == amounts.size() ) + //{ + // for (i=0; i 0) + { + + if (inputs < total) { //added dimxy + std::cerr << "AssetTransfer(): insufficient funds" << std::endl; + return (""); + } + if (inputs > total) + CCchange = (inputs - total); + //for (i=0; i &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid); +std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description); +std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); + +//this is in CCinclude.h int64_t AddTokenInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); + +//this is in CCinclude.h uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); + +/* +// CCassetsCore +CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,std::string name,std::string description); +CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector origpubkey); +bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); +//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); +bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CTransaction &tx); +int64_t IsAssetvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, int64_t &price, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid); +bool ValidateBidRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); +bool ValidateAskRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); +bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); +bool SetBidFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); +bool SetAskFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); +bool SetSwapFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); +int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid); +int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid); +bool AssetExactAmounts(bool compareTotals, struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid); + +// CCassetstx +int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); +int64_t AddAssetInputs(CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); +UniValue AssetOrders(uint256 tokenid); +UniValue AssetInfo(uint256 tokenid); +UniValue AssetList(); +std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description); +std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total); +std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode); + +std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal); +std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid); +std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount); +std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal); +std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal); +std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid); +std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillamount); +*/ + +#endif diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index a80b3b3cf..57a2a327b 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -144,9 +144,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { //fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2); privkey = cp->unspendablepriv2; - if ( othercond2 == 0 && cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR ) + if ( othercond2 == 0 && cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR && cp->evalcode != EVAL_ASSETS && cp->evalcode != EVAL_TOKENS) othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2); - else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR) ) + else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR || cp->evalcode == EVAL_ASSETS || cp->evalcode == EVAL_TOKENS) ) othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3); cond = othercond2; } @@ -297,7 +297,7 @@ int64_t CCfullsupply(uint256 tokenid) uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector origpubkey; std::string name,description; if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if ( DecodeAssetCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description) > 0 ) + if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description)) { return(tx.vout[0].nValue); } @@ -307,8 +307,11 @@ int64_t CCfullsupply(uint256 tokenid) int64_t CCtoken_balance(char *coinaddr,uint256 tokenid) { - int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; std::vector origpubkey; + int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock; + std::vector vopretExtra; std::vector > unspentOutputs; + uint8_t evalCode; + SetCCunspents(unspentOutputs,coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { @@ -316,7 +319,7 @@ int64_t CCtoken_balance(char *coinaddr,uint256 tokenid) if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN); - if ( DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,price,origpubkey) != 0 && assetid == tokenid ) + if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, vopretExtra) != 0 && assetid == tokenid ) { sum += it->second.satoshis; } diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index a1fa39192..47b9488c8 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -133,45 +133,63 @@ // tx validation -bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) +bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn) { static uint256 zero; - CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2; int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid; char destaddr[64],origaddr[64],CCaddr[64]; + CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2; + int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; + int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector origpubkey,tmporigpubkey,ignorepubkey; + uint8_t funcid, evalCodeInOpret; + char destaddr[64],origaddr[64],CCaddr[64]; + + // we need this for validating tokens' vins/vous: + struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + numvins = tx.vin.size(); numvouts = tx.vout.size(); outputs = inputs = 0; preventCCvins = preventCCvouts = -1; - if ( (funcid= DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,assetid2,remaining_price,origpubkey)) == 0 ) - return eval->Invalid("Invalid opreturn payload"); + + if((funcid = DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 ) + return eval->Invalid("AssetValidate: invalid opreturn payload"); + fprintf(stderr,"AssetValidate (%c)\n",funcid); - if ( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid,createTx,hashBlock) == 0 ) + + if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 ) return eval->Invalid("cant find asset create txid"); - else if ( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2,createTx,hashBlock) == 0 ) + else if( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2, createTx, hashBlock) == 0 ) return eval->Invalid("cant find asset2 create txid"); - else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) + else if( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("illegal asset vin0"); - else if ( numvouts < 1 ) + else if( numvouts < 1 ) return eval->Invalid("no vouts"); - else if ( funcid != 'c' ) + else if( funcid != 'c' ) { - if ( funcid == 't' ) + /* if( funcid == 't' ) starti = 0; - else starti = 1; - if ( assetid == zero ) + else + starti = 1; */ + + if( assetid == zero ) return eval->Invalid("illegal assetid"); - else if ( AssetExactAmounts(2, cp,inputs,starti,outputs,eval,tx,assetid) == false ) - return eval->Invalid("asset inputs != outputs"); + + else if (!AssetExactAmounts(cpAssets, inputs, outputs, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs + return false; // returns false if some problems with reading vintxes + } } - - switch ( funcid ) + switch( funcid ) { case 'c': // create wont be called to be verified as it has no CC inputs //vin.0: normal input //vout.0: issuance assetoshis to CC //vout.1: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['c'] [{"":""}] - return eval->Invalid("unexpected AssetValidate for createasset"); + //if (evalCodeInOpret == EVAL_ASSETS) + // return eval->Invalid("unexpected AssetValidate for createasset"); + // return + return eval->Invalid("invalid asset funcid \'c\'"); break; case 't': // transfer //vin.0: normal input @@ -179,9 +197,10 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.0 to n-2: assetoshis output to CC //vout.n-2: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid] - if ( inputs == 0 ) - return eval->Invalid("no asset inputs for transfer"); - fprintf(stderr,"transfer validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts); + //if (inputs == 0) + // return eval->Invalid("no asset inputs for transfer"); + //fprintf(stderr,"transfer preliminarily validated %.8f -> %.8f (%d %d)\n",(double)inputs/COIN,(double)outputs/COIN,preventCCvins,preventCCvouts); + return eval->Invalid("invalid asset funcid \'t\'"); break; case 'b': // buyoffer @@ -189,13 +208,13 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.0: amount of bid to unspendable //vout.1: normal output for change (if any) // vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey] - if ( remaining_price == 0 ) + if( remaining_price == 0 ) return eval->Invalid("illegal null amount for buyoffer"); - else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 ) + else if( ConstrainVout(tx.vout[0],1,cpAssets->unspendableCCaddr,0) == 0 ) return eval->Invalid("invalid vout for buyoffer"); preventCCvins = 1; preventCCvouts = 1; - fprintf(stderr,"buy offer validated to destaddr.(%s)\n",cp->unspendableCCaddr); + fprintf(stderr,"buy offer validated to destaddr.(%s)\n",cpAssets->unspendableCCaddr); break; case 'o': // cancelbuy @@ -204,9 +223,9 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] //vout.1: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['o'] - if ( (nValue= AssetValidateBuyvin(cp,eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 ) + if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) return(false); - else if ( ConstrainVout(tx.vout[0],0,origaddr,nValue) == 0 ) + else if( ConstrainVout(tx.vout[0],0, origaddr, nValue) == 0 ) return eval->Invalid("invalid refund for cancelbuy"); preventCCvins = 2; preventCCvouts = 0; @@ -224,32 +243,32 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.4: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey] preventCCvouts = 4; - if ( (nValue= AssetValidateBuyvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 ) + if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) return(false); - else if ( numvouts < 3 ) + else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillbuy"); - else if ( tmporigpubkey != origpubkey ) + else if( tmporigpubkey != origpubkey ) return eval->Invalid("mismatched origpubkeys for fillbuy"); else { - if ( nValue != tx.vout[0].nValue+tx.vout[1].nValue ) + if( nValue != tx.vout[0].nValue + tx.vout[1].nValue ) return eval->Invalid("locked value doesnt match vout0+1 fillbuy"); - else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) + else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 ) + if( ConstrainVout(tx.vout[2], 1, CCaddr, 0) == 0 ) return eval->Invalid("vout2 doesnt go to origpubkey fillbuy"); - else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue ) + else if ( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy"); } - else if ( ConstrainVout(tx.vout[2],1,CCaddr,inputs) == 0 ) + else if( ConstrainVout(tx.vout[2], 1, CCaddr, inputs) == 0 ) return eval->Invalid("vout2 doesnt match inputs fillbuy"); - else if ( ConstrainVout(tx.vout[1],0,0,0) == 0 ) + else if( ConstrainVout(tx.vout[1],0,0,0) == 0 ) return eval->Invalid("vout1 is CC for fillbuy"); - else if ( ValidateBidRemainder(remaining_price,tx.vout[0].nValue,nValue,tx.vout[1].nValue,tx.vout[2].nValue,totalunits) == false ) + else if( ValidateBidRemainder(remaining_price, tx.vout[0].nValue, nValue, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) return eval->Invalid("mismatched remainder for fillbuy"); - else if ( remaining_price != 0 ) + else if( remaining_price != 0 ) { - if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 ) + if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy"); } } @@ -266,16 +285,17 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey] //'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey] preventCCvouts = 1; - if ( remaining_price == 0 ) + if( remaining_price == 0 ) return eval->Invalid("illegal null remaining_price for selloffer"); - if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) + if( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) { preventCCvouts++; - if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 ) + if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); - else if ( tx.vout[0].nValue+tx.vout[1].nValue != inputs ) + else if( tx.vout[0].nValue + tx.vout[1].nValue != inputs ) return eval->Invalid("mismatched vout0+vout1 total for selloffer"); - } else if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,inputs) == 0 ) + } + else if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, inputs) == 0 ) return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); //fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price); break; @@ -286,9 +306,9 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] //vout.1: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] - if ( (assetoshis= AssetValidateSellvin(cp,eval,tmpprice,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 ) + if( (assetoshis= AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) return(false); - else if ( ConstrainVout(tx.vout[0],1,CCaddr,assetoshis) == 0 ) + else if( ConstrainVout(tx.vout[0], 1, CCaddr, assetoshis) == 0 ) return eval->Invalid("invalid vout for cancel"); preventCCvins = 2; preventCCvouts = 1; @@ -303,25 +323,25 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //'S'.vout.2: vin.2 value to original pubkey [origpubkey] //vout.3: normal output for change (if any) //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - if ( (assetoshis= AssetValidateSellvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 ) + if( (assetoshis = AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) return(false); - else if ( numvouts < 3 ) + else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillask"); - else if ( tmporigpubkey != origpubkey ) + else if( tmporigpubkey != origpubkey ) return eval->Invalid("mismatched origpubkeys for fillask"); else { - if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue ) + if( assetoshis != tx.vout[0].nValue + tx.vout[1].nValue ) return eval->Invalid("locked value doesnt match vout0+1 fillask"); - if ( ValidateAskRemainder(remaining_price,tx.vout[0].nValue,assetoshis,tx.vout[1].nValue,tx.vout[2].nValue,totalunits) == false ) + if( ValidateAskRemainder(remaining_price, tx.vout[0].nValue, assetoshis, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) return eval->Invalid("mismatched remainder for fillask"); - else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 ) + else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 ) return eval->Invalid("normal vout1 for fillask"); - else if ( ConstrainVout(tx.vout[2],0,origaddr,0) == 0 ) + else if( ConstrainVout(tx.vout[2], 0, origaddr, 0) == 0 ) return eval->Invalid("normal vout1 for fillask"); - else if ( remaining_price != 0 ) + else if( remaining_price != 0 ) { - if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 ) + if ( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr,0) == 0 ) return eval->Invalid("mismatched vout0 AssetsCCaddr for fill"); } } @@ -339,51 +359,58 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx //vout.3: CC output for asset2 change (if any) //vout.3/4: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['E'] [assetid vin0+1] [assetid vin2] [remaining asset2 required] [origpubkey] - if ( AssetExactAmounts(1, cp,inputs,1,outputs,eval,tx,assetid2) == false ) - eval->Invalid("asset2 inputs != outputs"); - if ( (assetoshis= AssetValidateSellvin(cp,eval,totalunits,tmporigpubkey,CCaddr,origaddr,tx,assetid)) == 0 ) + + //if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false ) + // eval->Invalid("asset2 inputs != outputs"); + + if( (assetoshis= AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) return(false); - else if ( numvouts < 3 ) + else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillex"); - else if ( tmporigpubkey != origpubkey ) + else if( tmporigpubkey != origpubkey ) return eval->Invalid("mismatched origpubkeys for fillex"); else { - if ( assetoshis != tx.vout[0].nValue+tx.vout[1].nValue ) + if( assetoshis != tx.vout[0].nValue + tx.vout[1].nValue ) return eval->Invalid("locked value doesnt match vout0+1 fillex"); - else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) + else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 ) + if( ConstrainVout(tx.vout[2], 1, CCaddr, 0) == 0 ) return eval->Invalid("vout2 doesnt go to origpubkey fillex"); - else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue ) + else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) { fprintf(stderr,"inputs %.8f != %.8f + %.8f\n",(double)inputs/COIN,(double)tx.vout[2].nValue/COIN,(double)tx.vout[3].nValue/COIN); return eval->Invalid("asset inputs doesnt match vout2+3 fillex"); } } - else if ( ConstrainVout(tx.vout[2],1,CCaddr,inputs) == 0 ) + else if( ConstrainVout(tx.vout[2], 1, CCaddr, inputs) == 0 ) return eval->Invalid("vout2 doesnt match inputs fillex"); - else if ( ConstrainVout(tx.vout[1],0,0,0) == 0 ) + else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 ) return eval->Invalid("vout1 is CC for fillex"); fprintf(stderr,"assets vout0 %llu, vin1 %llu, vout2 %llu -> orig, vout1 %llu, total %llu\n",(long long)tx.vout[0].nValue,(long long)assetoshis,(long long)tx.vout[2].nValue,(long long)tx.vout[1].nValue,(long long)totalunits); - if ( ValidateSwapRemainder(remaining_price,tx.vout[0].nValue,assetoshis,tx.vout[1].nValue,tx.vout[2].nValue,totalunits) == false ) + if( ValidateSwapRemainder(remaining_price, tx.vout[0].nValue, assetoshis,tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) return eval->Invalid("mismatched remainder for fillex"); - else if ( ConstrainVout(tx.vout[1],1,0,0) == 0 ) + else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 ) return eval->Invalid("normal vout1 for fillex"); - else if ( remaining_price != 0 ) + else if( remaining_price != 0 ) { - if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 ) + if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) return eval->Invalid("mismatched vout0 AssetsCCaddr for fillex"); } } fprintf(stderr,"fill validated\n"); break; + default: fprintf(stderr,"illegal assets funcid.(%c)\n",funcid); return eval->Invalid("unexpected assets funcid"); - break; + //break; } - return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); + + // what does this do? + bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts); + std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl; + return (bPrevent); } diff --git a/src/cc/eval.h b/src/cc/eval.h index 87b98349b..de1636ab8 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -55,7 +55,8 @@ EVAL(EVAL_PEGS, 0xee) \ EVAL(EVAL_MARMARA, 0xef) \ EVAL(EVAL_PAYMENTS, 0xf0) \ - EVAL(EVAL_GATEWAYS, 0xf1) + EVAL(EVAL_GATEWAYS, 0xf1) \ + EVAL(EVAL_TOKENS, 0xf2) typedef uint8_t EvalCode; diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 44f01a8a4..81318ad1e 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -14,203 +14,1315 @@ ******************************************************************************/ #include "CCHeir.h" +#include "CCassets.h" + +#include "heir_validate.h" + +class CoinHelper; +class TokenHelper; /* The idea of Heir CC is to allow crypto inheritance. A special 1of2 CC address is created that is freely spendable by the creator. The heir is only allowed to spend after the specified amount of idle blocks. The idea is that if the address doesnt spend any funds for a year (or whatever amount set), then it is time to allow the heir to spend. The design requires the heir to spend all the funds at once */ -// start of consensus code +// tx validation code -int64_t IsHeirvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) +// this is for indentation of debug log messages (in recursive calls): +//extern thread_local uint32_t assetValIndentSize; + +// check if vout is cc addr and also check sum(inputs) == sum(outputs) for the passed tx, if requested +int64_t IsHeirvout(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 tokenid, const CTransaction& tx, int32_t v) { - char destaddr[64]; - if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 ) - return(tx.vout[v].nValue); - } - return(0); + //std::string indentStr = std::string().append(assetValIndentSize, '.'); + + //std::cerr << indentStr << "IsHeirvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << std::boolalpha << " compareTotals=" << compareTotals << std::endl; + if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition()) + { + //std::cerr << indentStr << "IsHeirvout() IsPayToCryptoCondition=true for txid=" << tx.GetHash().GetHex() << std::endl; + /*if (compareTotals) { // totally there are only 2 levels actually + + // call recursively HeirExactTokenAmounts and compare ccinputs = ccoutputs for this tx: + assetValIndentSize++; + const bool isEqual = HeirExactTokenAmounts(false, cpHeir, eval, tokenid, tx); + assetValIndentSize--; + + if (!isEqual) { // ccInputs != ccOutputs means a problem + //std::cerr << indentStr << "IsHeirvout() warning: detected suspicious tx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs, checking further if it is the tokenbase tx" << std::endl; + // if ccInputs != ccOutputs and it is not the 'tokenbase' tx means it is possibly fake tx (dimxy): + if (tokenid != zeroid && tokenid != tx.GetHash()) { + std::cerr << indentStr << "IsHeirvout() warning: detected bad tx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx, skipping this tx" << std::endl; + return 0; + } + } + }*/ + + // TODO: add some validation here + + // lets check asset opreturn for this heir or assets tx (dimxy): + /* + int64_t dummyPrice; std::vector dummyOrigpubkey; + + const bool valOpret = ValidateAssetOpret(tx, v, tokenid, dummyPrice, dummyOrigpubkey); + //std::cerr << indentStr << "IsHeirvout() ValidateAssetOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << std::endl; + if (valOpret) { + std::cerr << indentStr << "IsHeirvout() opret is true, return value=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << std::endl; + return(tx.vout[v].nValue); + }*/ + + return(tx.vout[v].nValue); + } + //std::cerr << indentStr << "IsHeirvout() return value=0" << std::endl; + return(0); } -bool HeirExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) +// this function validates that tx cc outputs == cc inputs, +// that is there is no fake token supply from normal inputs (except the initial tokenbase tx) +// the cc inputs are allowed only from the Assets or Heir contracts +/*bool HeirExactTokenAmounts(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 tokenid, const CTransaction &tx) { - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) - { - //fprintf(stderr,"vini.%d check mempool\n",i); - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - //fprintf(stderr,"vini.%d check hash and vout\n",i); - if ( hashBlock == zerohash ) - return eval->Invalid("cant Heir from mempool"); - if ( (assetoshis= IsHeirvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - inputs += assetoshis; - } - } - } - for (i=0; iInvalid("mismatched inputs != outputs + txfee"); - } - else return(true); + static uint256 zerohash; + CTransaction vinTx; + uint256 hashBlock, activehash; + int64_t inputs = 0, outputs = 0, assetoshis; + + struct CCcontract_info *cpAssets, cAssets; + cpAssets = CCinit(&cAssets, EVAL_ASSETS); // init also tokens CC contract to check its cc addresses too + + std::string indentStr = std::string().append(assetValIndentSize, '.'); + + int32_t numvins = tx.vin.size(); + int32_t numvouts = tx.vout.size(); + for (int32_t i = 0; i < numvins; i++) + { + //std::cerr << indentStr << "HeirExactTokenAmounts() vin i=" << i << " cpHeir->ismyvin()=" << std::boolalpha << (*cpHeir->ismyvin)(tx.vin[i].scriptSig) << " cpAssets->ismyvin()=" << (*cpAssets->ismyvin)(tx.vin[i].scriptSig) << std::endl; + + // checking that vin is either from heir or assets: + if ((*cpHeir->ismyvin)(tx.vin[i].scriptSig) || (*cpAssets->ismyvin)(tx.vin[i].scriptSig)) + { + //std::cerr << indentStr; fprintf(stderr,"vini.%d check mempool\n",i); + if ((eval && !eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock)) || !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)) { + std::cerr << indentStr << "HeirExactTokenAmounts(): can't get vintx transaction txid=" << tx.vin[i].prevout.hash.GetHex() << std::endl; + return (eval) ? eval->Invalid("cant find vinTx") : false; + } + else + { + //std::cerr << indentStr; fprintf(stderr,"vini.%d check hash and vout\n",i); + if (hashBlock == zerohash) { + std::cerr << indentStr << "HeirExactTokenAmounts(): can't get vintx from mempool, txid=" << tx.vin[i].prevout.hash.GetHex() << std::endl; + return (eval) ? eval->Invalid("cant Heir from mempool") : false; + } + + std::string dummyRefcoin; uint256 dummyBindtxid, dummyDeposittxid; CPubKey dummyDestpub; int64_t dummyAmount; + uint256 dummyAssetid2; + std::vector dummyOrigpubkey; + + // Note: if tokenid is zeroid, it may mean we are on the first level and just called from HeirValidate, validating claim 't' tx, + // then let's find the tokenid ourselves: + if (tokenid == zeroid && DecodeAssetOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, dummyAssetid2, dummyAmount, dummyOrigpubkey) == 't') { + //std::cerr << indentStr << "HeirExactTokenAmounts() will check if this vinx is the tokenbase tokenid=" << tokenid.GetHex() << std::endl; + } + + // checking that the vout of the vintx (that is, referenced by this vin), in its turn, is fed by either from heir' or assets' cryptocondition address: + //std::cerr << indentStr << "HeirExactTokenAmounts() calling IsHeirvout for vintx i=" << i << " prevout.n=" << tx.vin[i].prevout.n << std::endl; + + assetValIndentSize++; + assetoshis = IsHeirvout(compareTotals, cpHeir, eval, tokenid, vinTx, tx.vin[i].prevout.n); + assetValIndentSize--; + if (assetoshis > 0) + inputs += assetoshis; + } + } + } + for (int32_t i = 0; iInvalid("mismatched inputs != outputs + txfee") : false; + } + else { + //std::cerr << indentStr << "HeirExactTokenAmounts() inputs=" << inputs << " vs outputs=" << outputs << " return true" << std::endl; + return(true); + } +}*/ + + +// claim coins tokens validation runner +// sadly we cannot have yet 'templatized' lambdas, if we could we could capture all these params inside HeirValidation() +template bool RunValidationPlans(uint8_t funcId, struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint256 latestTxid, CScript fundingOpretScript, bool isHeirSpendingBegan) +{ + int32_t numvins = tx.vin.size(); + int32_t numvouts = tx.vout.size(); + + // setup validation framework (please see its description in heir_validate.h): + // validation 'plans': + CInputValidationPlan vinPlan; + COutputValidationPlan voutPlan; + + // vin 'identifiers' + CNormalInputIdentifier normalInputIdentifier(cp); + CCCInputIdentifier ccInputIdentifier(cp); + + // vin and vout 'validators' + // always check coin inputs: + CMyPubkeyVoutValidator normalInputValidator(cp, fundingOpretScript, true); // check normal input for this opret cause this is first tx + //CMyPubkeyVoutValidator normalInputValidatorLast(cp, latestTxOpRetScript, true); // check normal input for latest opret. TODO: we may also check this opret + + CCC1of2AddressValidator cc1of2ValidatorThis(cp, fundingOpretScript, "checking this tx opreturn:"); // 1of2add validator with pubkeys from this tx opreturn + //CCC1of2AddressValidator cc1of2ValidatorLast(cp, latestTxOpRetScript, "checking last tx opreturn:"); // 1of2add validator with pubkeys from last tx opreturn + CHeirSpendValidator heirSpendValidator(cp, fundingOpretScript, latestTxid, isHeirSpendingBegan); // check if heir allowed to spend + + // only for tokens: + CMyPubkeyVoutValidator ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret + //CMyPubkeyVoutValidator ownerCCaddrValidatorLast(cp, latestTxOpRetScript, false); // check if this correct owner's cc user addr corresponding to lastest opret + // TODO: we may also check with current opret + COpRetValidator opRetValidator(cp, fundingOpretScript); // compare opRets in this and last tx + + switch (funcId) { + case 'F': // fund tokens + // vin validation plan: + // we need cast here this is casted inside + vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &normalInputValidator); // txfee - see AddNormalInput parameter + vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr + + // vout validation plan: + voutPlan.pushValidators(0, &cc1of2ValidatorThis); // check 1of2 addr funding + // do not check change at this time + // no checking for opret yet + break; + + case 'A': // add tokens + // vin validation plan: + // we need cast here this is casted inside + vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &normalInputValidator/*, &normalInputValidatorLast*/); // txfee - see AddNormalInput parameter + vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr + + // vout validation plan: + voutPlan.pushValidators(0, &cc1of2ValidatorThis); // check 1of2 addr funding + // do not check change at this time + voutPlan.pushValidators(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A: + break; + + case 'C': + // vin validation plan: + // we need cast here this is casted inside + vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &normalInputValidator/*&normalInputValidatorLast*/); // txfee - see AddNormalInput parameter + vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &cc1of2ValidatorThis /*, &cc1of2ValidatorLast*/); // cc1of2 funding addr + + // vout validation plan: + voutPlan.pushValidators(0, &heirSpendValidator); // check if heir is allowed to spend + voutPlan.pushValidators(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A + break; + } + + // call vin/vout validation + if (!vinPlan.validate(tx, eval)) + return false; + if (!voutPlan.validate(tx, eval)) + return false; + + return true; } -bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) +/** + * Tx validation entry function + */ +bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint32_t nIn) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64]; - return eval->Invalid("no validation yet"); - std::vector > txids; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - preventCCvins = preventCCvouts = -1; - if ( numvouts < 1 ) + int32_t numvins = tx.vin.size(); + int32_t numvouts = tx.vout.size(); + //int32_t preventCCvins = -1; + //int32_t preventCCvouts = -1; + + if (numvouts < 1) return eval->Invalid("no vouts"); - else - { - for (i=0; iInvalid("illegal normal vini"); - } + + if (chainActive.Height() < 741) + return true; + + uint8_t funcId; + uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, tokenid = zeroid; + + //CScript opRetScript = tx.vout[numvouts - 1].scriptPubKey; + + CScript fundingTxOpRetScript; + bool isHeirSpendingBegan = false; + + int32_t heirType = NOT_HEIR; + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, true); + if(funcId != 0) + heirType = HEIR_COINS; + else { + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, false); + if (funcId != 0) + heirType = HEIR_TOKENS; + } + + if (heirType == NOT_HEIR) + return eval->Invalid("invalid opreturn format"); + + if (funcId != 'F') { + if (fundingTxidInOpret == zeroid) { + return eval->Invalid("invalid tx opreturn format: no fundingtxid present"); } - //fprintf(stderr,"check amounts\n"); - if ( HeirExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"Heirget invalid amount\n"); - return false; - } - else - { - txid = tx.GetHash(); - memcpy(hash,&txid,sizeof(hash)); - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - fprintf(stderr,"Heirget validated\n"); - else fprintf(stderr,"Heirget invalid\n"); - return(retval); + if (heirType == HEIR_COINS) + latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, isHeirSpendingBegan); + else + latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, isHeirSpendingBegan); + + if (latestTxid == zeroid) { + return eval->Invalid("invalid heir transaction: no funding tx found"); } + } + else { + fundingTxOpRetScript = tx.vout[numvouts - 1].scriptPubKey; + } + + // validate prev tx cc inputs = outputs: + /* if (heirType == HEIR_TOKENS && funcId == 't' && !HeirExactTokenAmounts(true, cp, eval, zeroid, tx)) { + std::cerr << "HeirValidate() this tx or some of its vin tx has invalid cc amounts" << std::endl; + return eval->Invalid("this tx or some of its vin tx has invalid cc amounts"); + } */ + + switch (funcId) { + case 'F': + // fund coins: + // vins.*: normal inputs + // ----------------------------- + // vout.0: funding CC 1of2 addr for the owner and heir + // vout.1: txfee for CC addr used as a marker + // vout.2: normal change + // vout.n-1: opreturn 'F' ownerpk heirpk inactivitytime heirname + + // fund tokens: + // vin.0: normal inputs txfee + // vins.1+: user's CC addr inputs + // ----------------------- + // vout.0: funding heir CC 1of2 addr for the owner and heir + // vout.1: txfee for CC addr used as a marker + // vout.2: normal change + // vout.n-1: opreturn 't' tokenid 'F' ownerpk heirpk inactivitytime heirname tokenid + if (heirType == HEIR_TOKENS) + return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + else + return eval->Invalid("unexpected HeirValidate for heirfund"); + // break; + + case 'A': + // add funding coins: + // vins.*: normal inputs + // ------------------------ + // vout.0: funding CC 1of2 addr for the owner and heir + // vout.1: normal change + // vout.n-1: opreturn 'A' ownerpk heirpk inactivitytime fundingtx + + // add funding tokens: + // vins.0: normal inputs txfee + // vins.1+: user's CC addr inputs + // ------------------------ + // vout.0: funding CC 1of2 addr for the owner and heir + // vout.1: normal change + // vout.n-1: opreturn 't' tokenid 'A' ownerpk heirpk inactivitytime fundingtx + if (heirType == HEIR_TOKENS) + return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + else + return eval->Invalid("unexpected HeirValidate for heiradd"); + //break; + + case 'C': + // claim coins: + // vin.0: normal input txfee + // vin.1+: input from CC 1of2 addr + // ------------------------------------- + // vout.0: normal output to owner or heir address + // vout.1: change to CC 1of2 addr + // vout.2: change to user's addr from txfee input if any + // vout.n-1: opreturn 'C' ownerpk heirpk inactivitytime fundingtx + + // claim tokens: + // vin.0: normal input txfee + // vin.1+: input from CC 1of2 addr + // -------------------------------------------- + // vout.0: output to user's cc address + // vout.1: change to CC 1of2 addr + // vout.2: change to normal from txfee input if any + // vout.n-1: opreturn 't' tokenid 'C' ownerpk heirpk inactivitytime fundingtx + if (heirType == HEIR_TOKENS) + return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + else + return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + // break; + + default: + std::cerr << "HeirValidate() illegal heir funcid=" << (char)funcId << std::endl; + return eval->Invalid("unexpected HeirValidate funcid"); + // break; } + return eval->Invalid("unexpected"); // (PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts)); } // end of consensus code -// helper functions for rpc calls in rpcwallet.cpp -int64_t AddHeirInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) +// helper functions used in implementations of rpc calls (in rpcwallet.cpp) or validation code + +/** +* Checks if vout is to cryptocondition address +* @return vout value in satoshis +*/ +int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, int32_t voutIndex, CPubKey ownerPubkey, CPubKey heirPubkey) { - // add threshold check - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; - std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); - SetCCunspents(unspentOutputs,coinaddr); - for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; + char destaddr[65], heirContractAddr[65]; + + GetCCaddress1of2(cp, heirContractAddr, ownerPubkey, heirPubkey); + if (tx.vout[voutIndex].scriptPubKey.IsPayToCryptoCondition() != 0) { + // NOTE: dimxy it was unsafe 'Getscriptaddress(destaddr,tx.vout[voutIndex].scriptPubKey) > 0' here: + if (Getscriptaddress(destaddr, tx.vout[voutIndex].scriptPubKey) && strcmp(destaddr, heirContractAddr) == 0) + return (tx.vout[voutIndex].nValue); + } + return (0); +} + +// not used +bool HeirExactAmounts(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, int32_t minage, uint64_t txfee) +{ + static uint256 zerohash; + CTransaction vinTx; + uint256 hashBlock, activehash; + int32_t i, numvins, numvouts; + int64_t inputs = 0, outputs = 0, assetoshis; + numvins = tx.vin.size(); + numvouts = tx.vout.size(); + for (i = 0; i < numvins; i++) { + //fprintf(stderr,"HeirExactAmounts() vini.%d\n",i); + if ((*cp->ismyvin)(tx.vin[i].scriptSig) != 0) { + //fprintf(stderr,"HeirExactAmounts() vini.%d check mempool\n",i); + if (eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) + return eval->Invalid("cant find vinTx"); + else { + //fprintf(stderr,"HeirExactAmounts() vini.%d check hash and vout\n",i); + if (hashBlock == zerohash) + return eval->Invalid("cant Heir from mempool"); + ////if ( (assetoshis= IsHeirCCvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) + //// inputs += assetoshis; + } + } + } + for (i = 0; i < numvouts; i++) { + //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts); + ////if ( (assetoshis= IsHeirvout(cp,tx,i)) != 0 ) + //// outputs += assetoshis; + } + if (inputs != outputs + txfee) { + fprintf(stderr, "HeirExactAmounts() inputs %llu vs outputs %llu\n", (long long)inputs, (long long)outputs); + return eval->Invalid("mismatched inputs != outputs + txfee"); + } + else + return (true); +} + +// makes coin initial tx opret +CScript EncodeHeirCreateOpRet(uint8_t eval, uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) +{ + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName); +} + +// makes coin additional tx opret +CScript EncodeHeirOpRet(uint8_t eval, uint8_t funcid, uint256 fundingtxid) +{ + fundingtxid = revuint256(fundingtxid); + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)funcid << fundingtxid); +} +// makes opret for tokens while they are inside Heir contract address space - initial funding +CScript EncodeHeirAssetsCreateOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) +{ + tokenid = revuint256(tokenid); + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)'t' << tokenid << (uint8_t)funcid << ownerPubkey << heirPubkey << inactivityTimeSec << hearName); +} +// makes opret for tokens while they are inside Heir contract address space - additional funding +CScript EncodeHeirAssetsOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, uint256 fundingtxid) +{ + tokenid = revuint256(tokenid); + fundingtxid = revuint256(fundingtxid); + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)'t' << tokenid << (uint8_t)funcid << fundingtxid); +} + +/** +* decode opret vout for Heir contract +*/ +template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, bool noLogging) +{ + std::vector vopret; + uint8_t opretEval = 0; + uint8_t funcId = 0; + + fundingTxidInOpret = zeroid; //to init + + GetOpReturnData(scriptPubKey, vopret); + + if (vopret.size() > 1) { + // NOTE: it unmarshals for all F, A and C + Helper::UnmarshalOpret(vopret, opretEval, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret); + + /* + std::cerr << "DecodeHeirOpRet() e=" << (int)e + << " funcId=" << (char)funcId + << " ownerPubkey=" << HexStr(ownerPubkey) + << " heirPubkey=" << HexStr(heirPubkey) + << " heirName=" << heirName << " inactivityTime=" << inactivityTime << '\n'; + */ + + //if (e == EVAL_HEIR && IS_CHARINSTR(funcId, "FAC")) + if (opretEval == EVAL_HEIR && Helper::isMyFuncId(funcId)) { + tokenid = revuint256(tokenid); + fundingTxidInOpret = revuint256(fundingTxidInOpret); + return funcId; + } + else + { + if(!noLogging) std::cerr << "DecodeHeirOpRet() warning unexpected OP_RETURN eval=" << (int)opretEval << " or field type=" << (char)(funcId ? funcId : ' ') << '\n'; + } + } + else { + std::cerr << "DecodeHeirOpRet() unmarshal error (vopret.size() == 0)" << '\n'; + } + return (uint8_t)0; +} + +/** +* overload for 'F' opret +*/ +template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) +{ + uint256 dummytxid; + + return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, noLogging); +} + +/** +* overload for A, C oprets and AddHeirContractInputs +*/ +template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxidInOpret, bool noLogging) +{ + CPubKey dummyOwnerPubkey, dummyHeirPubkey; + int64_t dummyInactivityTime; + std::string dummyHeirName; + + return _DecodeHeirOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, noLogging); +} + + + +/** + * find the latest funding tx: it may be the first F tx or one of A or C tx's + * Note: this function is also called from validation code (use non-locking calls) + */ +template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, bool &isHeirSpendingBegan) +{ + CTransaction fundingtx; + uint256 hashBlock; + const bool allowSlow = false; + + //char markeraddr[64]; + //CCtxidaddr(markeraddr, fundingtxid); + //SetCCunspents(unspentOutputs, markeraddr); + + isHeirSpendingBegan = false; //init the var + funcId = 0; //init the var + + // get initial funding tx and set it as initial lasttx: + if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { + uint256 dummytxid; + + // set ownerPubkey and heirPubkey: + if ((funcId = DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) != 0) { + // found at least funding tx! + std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n'; + fundingOpretScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; + } else { + std::cerr << "FindLatestFundingTx() could not decode opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n'; + return zeroid; + } + } else { + std::cerr << "FindLatestFundingTx() could not find funding tx for fundingtxid=" << fundingtxid.GetHex() << '\n'; + return zeroid; + } + + std::vector> unspentOutputs; + struct CCcontract_info *cp, C; + cp = CCinit(&C, Helper::getMyEval()); + char coinaddr[64]; + GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' + + SetCCunspents(unspentOutputs, coinaddr); // get vector with tx's with unspent vouts of 1of2pubkey address: + //std::cerr << "FindLatestFundingTx() using 1of2address=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; + + int32_t maxBlockHeight = 0; // max block height + uint256 latesttxid = fundingtxid; + + // try to find the last funding or spending tx by checking fundingtxid in 'opreturn': + for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { + CTransaction regtx; + uint256 hash; + + uint256 txid = it->first.txhash; + //std::cerr << "FindLatestFundingTx() checking unspents for txid=" << txid.GetHex() << '\n'; + + int32_t blockHeight = (int32_t)it->second.blockHeight; + uint256 fundingTxidInOpret; + + //NOTE: maybe called from validation code: + if (myGetTransaction(txid, regtx, hash)) { + std::cerr << "FindLatestFundingTx() found tx for txid=" << txid.GetHex() << " blockHeight=" << blockHeight << " maxBlockHeight=" << maxBlockHeight << '\n'; + + { // debug code: + uint256 debAssetid; + uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, true); + std::cerr << "FindLatestFundingTx() regtx.vout.size()=" << regtx.vout.size() << " funcId=" << (char)(debfuncid ? debfuncid : ' ') << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << std::endl; + } + + uint256 dummyTokenid; // not to contaminate the tokenid from the params! + uint8_t tmpFuncId; + + if (regtx.vout.size() > 0 && + (tmpFuncId = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, true)) != 0 && + fundingtxid == fundingTxidInOpret) { + + // check if heir has begun spending: + if (Helper::isSpendingTx(tmpFuncId)) { // if 'C' or 't' opret + const CScript heirScriptPubkey = CScript() << ParseHex(HexStr(heirPubkey)) << OP_CHECKSIG; + + for (int32_t v = 0; v < regtx.vout.size() - 1; v++) { // do not check opret vout + if (heirScriptPubkey == regtx.vout[v].scriptPubKey) + isHeirSpendingBegan = true; + } + } + + if (blockHeight > maxBlockHeight) { + maxBlockHeight = blockHeight; + latesttxid = txid; + ///// fundingOpretScript = regtx.vout[regtx.vout.size() - 1].scriptPubKey; + funcId = tmpFuncId; + std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight << " opreturn type=" << (char)(funcId ? funcId : ' ') << " set as current lasttxid" << '\n'; + } + } + } + } + + return latesttxid; +} + +// overload for validation code +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, bool &isHeirSpendingBegan) +{ + uint8_t funcId; + CPubKey ownerPubkey; + CPubKey heirPubkey; + int64_t inactivityTime; + std::string heirName; + + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, isHeirSpendingBegan); +} + +// overload for transaction creation code +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool &isHeirSpendingBegan) +{ + CScript opRetScript; + + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, isHeirSpendingBegan); +} + +// add owner input in tokens +/*int64_t AddHeirTokenInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 refassetid, int64_t total, int32_t maxinputs) +{ + char coinaddr[64], destaddr[64]; int64_t threshold, nValue, price, totalinputs = 0; uint256 tokenid, txid, hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j, vout, n = 0; uint8_t evalcode, funcid; + std::vector > unspentOutputs; + GetCCaddress(cp, coinaddr, pk); + SetCCunspents(unspentOutputs, coinaddr); + threshold = total / (maxinputs + 1); + + //fprintf(stderr,"AddHeirTokenInputs() check cc addr=%s for token inputs\n",coinaddr); + for (std::vector >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + + if (it->second.satoshis < threshold) + continue; + for (j = 0; jsecond=" << it->second.satoshis << std::endl; + + if (strcmp(destaddr, coinaddr) != 0 && strcmp(destaddr, cp->unspendableCCaddr) != 0 && strcmp(destaddr, cp->unspendableaddr2) != 0) + continue; + GetOpReturnData(vintx.vout[vintx.vout.size() - 1].scriptPubKey, vopret); + + // NOTE: special opret decode: + // we should not check for E_UNMARSHAL return code because it returns false if not EOF, + // but we have our remainder after tokenid! + bool isEof = false; + bool unmarshalResult = E_UNMARSHAL(vopret, ss >> evalcode; ss >> funcid; ss >> tokenid; isEof=ss.eof()); + if (unmarshalResult || !isEof) + { + tokenid = revuint256(tokenid); // usually DecodeOpretXXX() funcs do this + + //std::cerr << "AddHeirTokenInputs() vout=" << vout << " evalcode=" << (int)evalcode << " cp->evalcode=" << (int)cp->evalcode << " funcid=" << (char)funcid << " check for refassetid=" << refassetid.GetHex() << " vs tokenid in opret=" << tokenid.GetHex() << " coins=" << (double)vintx.vout[vout].nValue / COIN << std::endl; + if (tokenid == refassetid && + IS_CHARINSTR(funcid, "tGB") && + (nValue = vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) + { + std::cerr << "AddHeirTokenInputs() total=" << total << " maxinputs=" << maxinputs << " uxto value=" << it->second.satoshis << std::endl; + if (total != 0 && maxinputs != 0) + mtx.vin.push_back(CTxIn(txid, vout, CScript())); + //nValue = it->second.satoshis; + totalinputs += nValue; + n++; + if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) + break; + } + } + } + } + return(totalinputs); +}*/ + +// add inputs of 1 of 2 cc address +template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, uint256 fundingtxid, CMutableTransaction& mtx, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t total, int32_t maxinputs) +{ + // TODO: add threshold check + int64_t nValue, voutValue, totalinputs = 0; + CTransaction vintx; + int32_t n = 0; + std::vector> unspentOutputs; + + char coinaddr[64]; + GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 pubkey of 2 pubkeys' + SetCCunspents(unspentOutputs, coinaddr); + + // char markeraddr[64]; + // CCtxidaddr(markeraddr, fundingtxid); + // SetCCunspents(unspentOutputs, markeraddr); + //std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; + + for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { + uint256 txid = it->first.txhash; + uint256 hashBlock; + int32_t voutIndex = (int32_t)it->first.index; // no need to prevent dup - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) - { - if ( (nValue= IsHeirvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 ) - { - if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,vout,CScript())); + // dimxy: maybe it is good to put tx's in cache? + if (GetTransaction(txid, vintx, hashBlock, false) != 0) { + uint256 tokenid; + uint256 fundingTxidInOpret; + + uint8_t funcId = DecodeHeirOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, true); + // note: it returns in in satoshis too... + if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && // we're spending only tx's in this funding plan + funcId != 0 && + Helper::isMyFuncId(funcId) && + // deep validation for tokens: + (typeid(Helper) == typeid(TokenHelper) && IsHeirvout(true, cp, nullptr, tokenid, vintx, voutIndex) > 0) && + (voutValue = IsHeirFundingVout(cp, vintx, voutIndex, ownerPubkey, heirPubkey)) > 0 && + !myIsutxo_spentinmempool(txid, voutIndex)) + { + std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; + if (total != 0 && maxinputs != 0) + mtx.vin.push_back(CTxIn(txid, voutIndex, CScript())); nValue = it->second.satoshis; totalinputs += nValue; n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) + if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) break; } } } - return(totalinputs); + return totalinputs; } -std::string HeirGet(uint64_t txfee,int64_t nValue) +/** + * enumerate all tx's sending to CCHeir 1of2address and calc total lifetime funds + */ +template int64_t LifetimeHeirContractFunds(struct CCcontract_info* cp, uint256 fundingtxid, CPubKey ownerPubkey, CPubKey heirPubkey) { - CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,Heirpk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; - cp = CCinit(&C,EVAL_HEIR); - if ( txfee == 0 ) - txfee = 10000; - Heirpk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddHeirInputs(cp,mtx,Heirpk,nValue+txfee,60)) > 0 ) - { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,CCchange,Heirpk)); - 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_HEIR << (uint8_t)'G' << j)); - if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 ) + char coinaddr[64]; + GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' + + std::vector> addressIndexes; + SetCCtxids(addressIndexes, coinaddr); + + //fprintf(stderr,"LifetimeHeirContractFunds() scan lifetime of %s\n",coinaddr); + int64_t total = 0; + for (std::vector>::const_iterator it = addressIndexes.begin(); it != addressIndexes.end(); it++) { + uint256 hashBlock; + uint256 txid = it->first.txhash; + CTransaction tx; + + if (GetTransaction(txid, tx, hashBlock, false) && tx.vout.size() > 0) { + uint8_t funcId; + uint256 tokenid; + uint256 fundingTxidInOpret; + const int32_t ivout = 0; + + funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, true); + + //std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n'; + + if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && Helper::isMyFuncId(funcId) && !Helper::isSpendingTx(funcId) + /* && !myIsutxo_spentinmempool(txid, ccVoutIdx) */) // include also tx in mempool { - 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]); + total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change) + std::cerr << "LifetimeHeirContractFunds() added tx=" << txid.GetHex() << " it->second=" << it->second << " vout[0].nValue=" << tx.vout[ivout].nValue << " opreturn=" << (char)funcId << '\n'; } } - fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL)); - return(""); - } else fprintf(stderr,"cant find Heir inputs\n"); - return(""); -} - -std::string HeirFund(uint64_t txfee,int64_t funds) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,Heirpk; CScript opret; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_HEIR); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - Heirpk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,funds,Heirpk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); } - return(""); + return (total); } -UniValue HeirInfo() +/* rpc functions' implementation: */ + +/** + * heirfund rpc call implementation + * creates tx for initial funds deposit on cryptocondition address which locks funds for spending by either of address. + * and also for setting spending plan for the funds' owner and heir + * @return fundingtxid handle for subsequent references to this heir funding plan + */ +template std::string HeirFund(uint64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); char numstr[64]; - CPubKey Heirpk; struct CCcontract_info *cp,C; int64_t funding; - result.push_back(Pair("result","success")); - result.push_back(Pair("name","Heir")); - cp = CCinit(&C,EVAL_HEIR); - Heirpk = GetUnspendable(cp,0); - funding = AddHeirInputs(cp,mtx,Heirpk,0,0); - sprintf(numstr,"%.8f",(double)funding/COIN); - result.push_back(Pair("funding",numstr)); - return(result); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + struct CCcontract_info *cp, C; + + cp = CCinit(&C, Helper::getMyEval()); + if (txfee == 0) + txfee = 10000; + + //std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl; + + if (!heirPubkey.IsValid()) { + std::cerr << "HeirFund() heirPubkey is not valid!" << std::endl; + return std::string(""); + } + + CPubKey myPubkey = pubkey2pk(Mypubkey()); + + if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners + int64_t inputs, change; + + if ((inputs=Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners + //mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,amount,HeirCCpk)); + mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk + + // add a marker for finding all plans in HeirList() + CPubKey HeirContractPubKey = GetUnspendable(cp, 0); + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(HeirContractPubKey)) << OP_CHECKSIG)); // TODO: do we need this marker? + + // calc and add change vout: + if (inputs > amount) + change = (inputs - amount); // -txfee <-- txfee pays user + + //std::cerr << "HeirFund() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; + + if (change != 0) { // vout[1] + mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); + } + + // add change for txfee and opreturn vouts and sign tx: + return (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, + // CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'F' << myPubkey << heirPubkey << inactivityTimeSec << heirName))); + Helper::makeCreateOpRet(tokenid, myPubkey, heirPubkey, inactivityTimeSec, heirName))); + } + else // TODO: need result return unification with heiradd and claim + std::cerr << "HeirFund() could not find owner inputs" << std::endl; + + } + else + std::cerr << "HeirFund() could not find normal inputs" << std::endl; + return std::string(""); +} + +// if no these callers - it could not link +std::string HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){ + return HeirFund(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid); +} + +std::string HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) { + return HeirFund(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid); +} + +/** + * heiradd rpc call implementation + * creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir + * @return result object with raw tx or error text + */ +template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount) +{ + UniValue result(UniValue::VOBJ); //, a(UniValue::VARR); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey ownerPubkey, heirPubkey; + int64_t inputs, CCchange = 0; + int64_t inactivityTimeSec; + struct CCcontract_info *cp, C; + std::string rawhex; + uint256 lasttxid, tokenid; + std::string heirName; + uint8_t funcId; + bool isHeirSpendingBegan = false; + + cp = CCinit(&C, Helper::getMyEval()); + if (txfee == 0) + txfee = 10000; + + if ((lasttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan)) != zeroid) { + int32_t numblocks; + + CPubKey myPubkey = pubkey2pk(Mypubkey()); + + // check if it is the owner + if (myPubkey != ownerPubkey) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "adding funds is only allowed for the owner of this contract")); + return result; + } + + if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners + + int64_t inputs, change; + + //if (AddNormalinputs(mtx, myPubkey, amount + 1 * txfee, 64) > 0) { // TODO: why 64 max inputs? + if ((inputs = Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, 64)) > 0) { // TODO: why 64 max inputs? + + // we do not use markers anymore - storing data in opreturn is better + // add marker vout: + /* char markeraddr[64]; + CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners + std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */ + + // add cryptocondition to spend this funded amount for either pk + mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), amount, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! + + // calc and add change vout: + if (inputs > amount) + change = (inputs - amount); // -txfee <-- txfee pays user + + //std::cerr << "HeirAdd() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; + + if (change != 0) { // vout[1] + mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); + } + + // add opreturn 'A' and sign tx: // this txfee ignored + std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, + Helper::makeAddOpRet(tokenid, fundingtxid))); + + result.push_back(Pair("result", "success")); + result.push_back(Pair("hextx", rawhextx)); + } + else { + std::cerr << "HeirAdd cannot find owner inputs" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find owner inputs")); + } + } + else { + std::cerr << "HeirAdd cannot find normal inputs for tx fee" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find normal inputs for tx fee")); + } + + } else { + fprintf(stderr, "HeirAdd() can't find any heir CC funding tx's\n"); + + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find any heir CC funding transactions")); + } + + return result; +} + + +UniValue HeirAddCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { + return HeirAdd(fundingtxid, txfee, amount); +} +UniValue HeirAddTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { + return HeirAdd(fundingtxid, txfee, amount); +} + + +/** + * heirclaim rpc call implementation + * creates tx to spend funds from cryptocondition address by either funds' owner or heir + * @return result object with raw tx or error text + */ +template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t amount) +{ + UniValue result(UniValue::VOBJ); //, a(UniValue::VARR); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey myPubkey, ownerPubkey, heirPubkey; + int64_t inputs, change = 0; + int64_t inactivityTimeSec; + struct CCcontract_info *cp, C; + + uint256 latesttxid, tokenid; + uint8_t funcId; + std::string heirName; + bool isHeirSpendingBegan = false; + + + cp = CCinit(&C, Helper::getMyEval()); + if (txfee == 0) + txfee = 10000; + + if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan)) != zeroid) { + int32_t numblocks; + uint64_t durationSec = 0; + + // we do not need to find duration if spending already has begun + if (!isHeirSpendingBegan) { + durationSec = CCduration(numblocks, latesttxid); + std::cerr << "HeirClaim() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << std::endl; + } + + // spending is allowed if there is already spending tx or inactivity time + //bool isAllowedToHeir = (funcId == 'C' || durationSec > inactivityTimeSec) ? true : false; + bool isAllowedToHeir = (isHeirSpendingBegan || durationSec > inactivityTimeSec) ? true : false; + myPubkey = pubkey2pk(Mypubkey()); + + // if it is the heir, check if spending not allowed to heir yet + if (myPubkey == heirPubkey && !isAllowedToHeir) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "spending is not allowed yet for the heir")); + return result; + } + + // we do not use markers any more: + // we allow owner to spend funds at any time: + // if it is the owner, check if spending already allowed to heir + /* if (myPubkey == ownerPubkey && isAllowedToHeir) { + result.push_back(Pair("result", "spending is not already allowed for the owner")); + return result; + } */ + + // add spending txfee from the calling user + if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { + + // add spending from cc 1of2 address + if ((inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, amount, 60)) >= amount) // TODO: why only 60 inputs? + { + /*if (inputs < amount) { + std::cerr << "HeirClaim() cant find enough HeirCC 1of2 inputs, found=" << inputs << " required=" << amount << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find heir CC funding")); + + return result; + }*/ + + // add vout with amount to claiming address + mtx.vout.push_back(Helper::makeClaimerVout(amount, myPubkey)); // vout[0] + + // calc and add change vout: + if (inputs > amount) + change = (inputs - amount); // -txfee <-- txfee pays user + + //std::cerr << "HeirClaim() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; + + // change to 1of2 funding addr: + if (change != 0) { // vout[1] + mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! + } + + // add marker vout: + /*char markeraddr[64]; + CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); + // NOTE: amount = 0 is not working: causes error code: -26, error message : 64 : dust + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners + std::cerr << "HeirClaim() adding markeraddr=" << markeraddr << '\n'; */ + + uint8_t myprivkey[32]; + char coinaddr[64]; + // set priv key addresses in CC structure: + GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + Myprivkey(myprivkey); + + //fprintf(stderr,"HeirClaim() before setting unspendable CC addr2= (%s) addr3= (%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); + CCaddr2set(cp, Helper::getMyEval(), ownerPubkey, myprivkey, coinaddr); + CCaddr3set(cp, Helper::getMyEval(), heirPubkey, myprivkey, coinaddr); + + fprintf(stderr, "HeirClaim() after setting unspendable CC addr2=(%s) addr3=(%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); + + // add opreturn 'C' and sign tx: // this txfee will be ignored + std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, + Helper::makeClaimOpRet(tokenid, fundingtxid)); + + result.push_back(Pair("result", "success")); + result.push_back(Pair("hextx", rawhextx)); + + } else { + fprintf(stderr, "HeirClaim() cant find Heir CC inputs\n"); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find heir CC funding")); + } + } else { + fprintf(stderr, "HeirClaim() cant find sufficient user inputs for tx fee\n"); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find sufficient user inputs to pay transaction fee")); + } + } else { + fprintf(stderr, "HeirClaim() can't find any heir CC funding tx's\n"); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find any heir CC funding transactions")); + } + + return result; +} + +UniValue HeirClaimCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { + return HeirClaim(fundingtxid, txfee, amount); +} +UniValue HeirClaimTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { + return HeirClaim(fundingtxid, txfee, amount); +} + + + +/** + * heirinfo rpc call implementation + * returns some information about heir CC contract plan by a handle of initial fundingtxid: + * plan name, owner and heir pubkeys, funds deposited and available, flag if spending is enabled for the heir + * @return heir info data + */ +UniValue HeirInfo(uint256 fundingtxid) +{ + UniValue result(UniValue::VOBJ); + + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey ownerPubkey, heirPubkey; + uint256 latestFundingTxid; + uint256 dummyTokenid, tokenid; + + std::string heirName; + uint8_t funcId; + int64_t inactivityTimeSec; + + CTransaction fundingtx; + uint256 hashBlock; + const bool allowSlow = false; + + //char markeraddr[64]; + //CCtxidaddr(markeraddr, fundingtxid); + //SetCCunspents(unspentOutputs, markeraddr); + + // get initial funding tx and set it as initial lasttx: + if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { + + int32_t heirType = NOT_HEIR; + if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true) == 'F') + heirType = HEIR_COINS; + else if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true) == 'F') + heirType = HEIR_TOKENS; + else + { + std::cerr << "HeirInfo() initial tx F not found for this fundingtx" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "initial tx F not found")); + return result; + } + + struct CCcontract_info *cp, C; + if (heirType == HEIR_COINS) + cp = CCinit(&C, CoinHelper::getMyEval()); + else + cp = CCinit(&C, TokenHelper::getMyEval()); + + bool isHeirSpendingBegan = false; + + if (heirType == HEIR_COINS) + latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan); + else + latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan); + + if (latestFundingTxid != zeroid) { + int32_t numblocks; + uint64_t durationSec = 0; + + std::cerr << "HeirInfo() latesttxid=" << latestFundingTxid.GetHex() << '\n'; + + std::ostringstream stream; + std::string msg; + + result.push_back(Pair("fundingtxid", fundingtxid.GetHex())); + result.push_back(Pair("name", heirName.c_str())); + + if (heirType == HEIR_TOKENS) { + stream << tokenid.GetHex(); + msg = "tokenid"; + result.push_back(Pair(msg, stream.str().c_str())); + stream.str(""); + stream.clear(); + } + + char hexbuf[67]; + stream << pubkey33_str(hexbuf, (uint8_t*)ownerPubkey.begin()); + result.push_back(Pair("owner", stream.str().c_str())); + stream.str(""); + stream.clear(); + + stream << pubkey33_str(hexbuf, (uint8_t*)heirPubkey.begin()); + result.push_back(Pair("heir", stream.str().c_str())); + stream.str(""); + stream.clear(); + + int64_t total; + if (heirType == HEIR_COINS) + total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); + else + total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); + + if (heirType == HEIR_COINS) { + msg = "funding total in coins"; + stream << (double)total / COIN; + } + else { + msg = "funding total in tokens"; + stream << total; + } + result.push_back(Pair(msg, stream.str().c_str())); + stream.str(""); + stream.clear(); + + int64_t inputs; + if (heirType == HEIR_COINS) + inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60); //NOTE: amount = 0 means all unspent inputs + else + inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60); + + if (heirType == HEIR_COINS) { + msg = "funding available in coins"; + stream << (double)inputs / COIN; + } + else { + msg = "funding available in tokens"; + stream << inputs; + } + result.push_back(Pair(msg, stream.str().c_str())); + stream.str(""); + stream.clear(); + + if (heirType == HEIR_TOKENS) { + int64_t ownerInputs = TokenHelper::addOwnerInputs(cp, tokenid, mtx, ownerPubkey, 0, (int32_t)64); + stream << ownerInputs; + msg = "owner funding available in tokens"; + result.push_back(Pair(msg, stream.str().c_str())); + stream.str(""); + stream.clear(); + } + + stream << inactivityTimeSec; + result.push_back(Pair("inactivity time setting", stream.str().c_str())); + stream.str(""); + stream.clear(); + + if (!isHeirSpendingBegan) { // we do not need find duration if the spending already has begun + durationSec = CCduration(numblocks, latestFundingTxid); + std::cerr << "HeirInfo() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << '\n'; + } + + stream << std::boolalpha << (isHeirSpendingBegan || durationSec > inactivityTimeSec); + result.push_back(Pair("spending allowed for the heir", stream.str().c_str())); + stream.str(""); + stream.clear(); + + result.push_back(Pair("result", "success")); + } + else { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "could not find heir cc plan for this txid")); + } + } + else { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "could not find heir cc plan for this txid (no initial tx)")); + } + return (result); +} + +/** + * heirlist rpc call implementation + * @return list of heir plan handles (fundingtxid) + */ + +template void _HeirList(struct CCcontract_info *cp, UniValue &result) +{ + std::vector> unspentOutputs; + char coinaddr[64]; + CPubKey ccPubKeyEmpty; + GetCCaddress(cp, coinaddr, ccPubKeyEmpty); + SetCCunspents(unspentOutputs, cp->normaladdr); + + std::cerr << "HeirList() finding heir marker from Heir contract addr=" << cp->normaladdr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; + + // TODO: move marker to special cc addr to prevent checking all tokens + for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { + uint256 hashBlock; + uint256 txid = it->first.txhash; + uint256 tokenid; + int32_t vout = (int32_t)it->first.index; + + std::cerr << "HeirList() checking txid=" << txid.GetHex() << " vout=" << vout << '\n'; + + CTransaction vintx; + if (GetTransaction(txid, vintx, hashBlock, false) != 0 && (vintx.vout.size() - 1) > 0) { + CPubKey ownerPubkey, heirPubkey; + std::string heirName; + int64_t inactivityTimeSec; + + uint8_t funcId = DecodeHeirOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + + // note: if it is not Heir token funcId would be equal to 0 + if (funcId == 'F') { + result.push_back(Pair("fundingtxid heirName", txid.GetHex() + std::string(" ") + (typeid(Helper) == typeid(TokenHelper) ? std::string("token") : std::string("coin")) + std::string(" ") + heirName)); + } + else { + fprintf(stderr, "HeirList() couldnt find initial transaction\n"); + } + } + else { + fprintf(stderr, "HeirList() couldnt load transaction\n"); + } + } +} + + +UniValue HeirList() +{ + UniValue result(UniValue::VOBJ); + result.push_back(Pair("result", "success")); + + struct CCcontract_info *cpHeir, *cpTokens, C; + + cpHeir = CCinit(&C, EVAL_HEIR); + cpTokens = CCinit(&C, EVAL_TOKENS); + + _HeirList(cpHeir, result); + _HeirList(cpTokens, result); + + return result; } diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h new file mode 100644 index 000000000..8b432e8e0 --- /dev/null +++ b/src/cc/heir_validate.h @@ -0,0 +1,622 @@ +#ifndef HEIR_VALIDATE_H +#define HEIR_VALIDATE_H + +#include "CCinclude.h" +#include "CCHeir.h" + +#define NOT_HEIR (-1) +#define HEIR_COINS 1 +#define HEIR_TOKENS 2 +#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos) + + +// makes coin initial tx opret +CScript EncodeHeirCreateOpRet(uint8_t eval, uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); +// makes coin additional tx opret +CScript EncodeHeirOpRet(uint8_t eval, uint8_t funcid, uint256 fundingtxid); + +CScript EncodeHeirAssetsCreateOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName); +CScript EncodeHeirAssetsOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, uint256 fundingtxid); +//CScript EncodeHeirConvertedAssetsOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 fundingtxid); + +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, bool &isHeirSpendingBegan); +template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxid, bool noLogging = false); +//template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); +template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); + +//int64_t AddHeirTokenInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 reftokenid, int64_t total, int32_t maxinputs); + + +// helper class to allow polymorphic behaviour for HeirXXX() functions in case of coins +class CoinHelper { +public: + + static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); } + static uint8_t getMyEval() { return EVAL_HEIR; } + static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { + return AddNormalinputs(mtx, ownerPubkey, total, maxinputs); + } + + static CScript makeCreateOpRet(uint256 dummyid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { + return EncodeHeirCreateOpRet((uint8_t)EVAL_HEIR, (uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + } + static CScript makeAddOpRet(uint256 dummyid, uint256 fundingtxid) { + return EncodeHeirOpRet((uint8_t)EVAL_HEIR, (uint8_t)'A', fundingtxid); + } + static CScript makeClaimOpRet(uint256 dummyid, uint256 fundingtxid) { + return EncodeHeirOpRet((uint8_t)EVAL_HEIR, (uint8_t)'C', fundingtxid); + } + + static void UnmarshalOpret(std::vector vopret, uint8_t &e, uint8_t &funcId, uint256 &dummytokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret) { + E_UNMARSHAL(vopret, { ss >> e; ss >> funcId; ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; if (IS_CHARINSTR(funcId, "F")) { ss >> heirName; } if (IS_CHARINSTR(funcId, "AC")) { ss >> fundingTxidInOpret; } }); + } + + static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } + + 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); + } +}; + +// helper class to allow polymorphic behaviour for HeirXXX() functions in case of tokens +class TokenHelper { +public: + + static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); } + static uint8_t getMyEval() { return EVAL_TOKENS; } + static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { + return AddTokenCCInputs(cp, mtx, ownerPubkey, tokenid, total, maxinputs); + } + + static CScript makeCreateOpRet(uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { + return EncodeHeirAssetsCreateOpRet((uint8_t)EVAL_HEIR, (uint8_t)'F', tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + } + static CScript makeAddOpRet(uint256 tokenid, uint256 fundingtxid) { + return EncodeHeirAssetsOpRet((uint8_t)EVAL_HEIR, (uint8_t)'A', tokenid, fundingtxid); + } + static CScript makeClaimOpRet(uint256 tokenid, uint256 fundingtxid) { + return EncodeHeirAssetsOpRet((uint8_t)EVAL_HEIR, (uint8_t)'C', tokenid, fundingtxid); + } + + static void UnmarshalOpret(std::vector vopret, uint8_t &e, uint8_t &funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingtxidInOpret) { + uint8_t assetFuncId = '\0'; + bool result = E_UNMARSHAL(vopret, { ss >> e; ss >> assetFuncId; ss >> tokenid; ss >> funcId; if (IS_CHARINSTR(funcId, "F")) { ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; } if (IS_CHARINSTR(funcId, "AC")) { ss >> fundingtxidInOpret; } }); + if (!result /*|| assetFuncId != 't' -- any tx is ok*/) + funcId = 0; + } + static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } + + static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) { + return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); + } + static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) { + return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); + } +}; + +//#define OPTIONAL_VOUT 0 // if vout is optional then in a validation plan it will be skipped without error, if all validators return false + + + +/** +* 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 +*/ +/** + * 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, CTxOut prevVout, std::string& message) const = 0; + virtual bool validateVout(CTxOut vout, 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], 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], 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, std::string& message) const + { + //std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl; + uint8_t funcId; + CPubKey ownerPubkey, heirPubkey; + int64_t inactivityTime; + std::string heirName; + uint256 tokenid; + + if ((funcId = DecodeHeirOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) == 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); + 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, CTxOut prevVout, 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, std::string& message) const + { + //std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl; + + uint8_t funcId; + CPubKey ownerPubkey, heirPubkey; + int64_t inactivityTime; + std::string heirName; + uint256 tokenid; + + ///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl; + // get both pubkeys: + if ((funcId = DecodeHeirOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) == 0) { + message = std::string("invalid opreturn format"); + return false; + } + + CScript ownerScript; + CScript heirScript; + if (m_checkNormals) { + ownerScript = CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey; + heirScript = CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey; + } + 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=" << Helper::makeUserVout(vout.nValue, ownerPubkey).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; + return false; + } + virtual bool validateVin(CTxIn vin, CTxOut prevVout, 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, bool isHeirSpendingBegan) + : m_fundingOpretScript(opRetScript), m_latesttxid(latesttxid), m_isHeirSpendingBegan(isHeirSpendingBegan), CValidatorBase(cp) {} + + virtual bool isVinValidator() const { return false; } + virtual bool validateVout(CTxOut vout, std::string& message) const + { + //std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl; + + uint8_t funcId; + CPubKey ownerPubkey, heirPubkey; + int64_t inactivityTime; + std::string heirName; + uint256 tokenid; + + + // get heir pubkey: + if ((funcId = DecodeHeirOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, false)) == 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::makeClaimerVout(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, CTxOut prevVout, std::string& message) const { return true; } + +private: + CScript m_fundingOpretScript; + uint256 m_latesttxid; + bool 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, std::string& message) const + { + //std::cerr << "COpRetValidator::validateVout() entered" << std::endl; + + uint8_t funcId, initialFuncId; // do not check heir name + uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid, initialTokenid; + + if ((funcId = DecodeHeirOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret)) == 0) { + message = std::string("invalid opreturn format"); + return false; + } + if ((initialFuncId = DecodeHeirOpRet(m_fundingOpretScript, initialTokenid, dummyTxid)) == 0) { + message = std::string("invalid initial tx opreturn format"); + return false; + } + + // validation rules: + if (!Helper::isMyFuncId(funcId)) { + message = std::string("invalid funcid in opret"); + return false; + } + + 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, CTxOut prevVout, std::string& message) const { return true; } + +private: + CScript m_fundingOpretScript; +}; + + + +#endif \ No newline at end of file diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 94403bcc0..5c32b2f5a 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -406,8 +406,16 @@ static const CRPCCommand vRPCCommands[] = { "faucet", "faucetget", &faucetget, true }, { "faucet", "faucetaddress", &faucetaddress, true }, - // Heir - { "heir", "heiraddress", &heiraddress, true }, + // Heir + { "heir", "heiraddress", &heiraddress, true }, + { "heir", "heirfund", &heirfund, true }, + { "heir", "heiradd", &heiradd, true }, + { "heir", "heirclaim", &heirclaim, true }, + { "heir", "heirfundtokens", &heirfundtokens, true }, + { "heir", "heiraddtokens", &heiraddtokens, true }, + { "heir", "heirclaimtokens", &heirclaimtokens, true }, + { "heir", "heirinfo", &heirinfo, true }, + { "heir", "heirlist", &heirlist, true }, // Channels { "channels", "channelsaddress", &channelsaddress, true }, @@ -479,7 +487,8 @@ static const CRPCCommand vRPCCommands[] = { "dice", "dicestatus", &dicestatus, true }, { "dice", "diceaddress", &diceaddress, true }, - // tokens + // tokens & assets + { "tokens", "assetsaddress", &assetsaddress, true }, { "tokens", "tokeninfo", &tokeninfo, true }, { "tokens", "tokenlist", &tokenlist, true }, { "tokens", "tokenorders", &tokenorders, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 920aac970..7c85c43b6 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -242,6 +242,7 @@ extern UniValue tokeninfo(const UniValue& params, bool fHelp); extern UniValue tokenlist(const UniValue& params, bool fHelp); extern UniValue tokenorders(const UniValue& params, bool fHelp); extern UniValue tokenbalance(const UniValue& params, bool fHelp); +extern UniValue assetsaddress(const UniValue& params, bool fHelp); extern UniValue tokenaddress(const UniValue& params, bool fHelp); extern UniValue tokencreate(const UniValue& params, bool fHelp); extern UniValue tokentransfer(const UniValue& params, bool fHelp); @@ -253,6 +254,14 @@ extern UniValue tokencancelask(const UniValue& params, bool fHelp); extern UniValue tokenfillask(const UniValue& params, bool fHelp); extern UniValue tokenconvert(const UniValue& params, bool fHelp); extern UniValue heiraddress(const UniValue& params, bool fHelp); +extern UniValue heirfund(const UniValue& params, bool fHelp); +extern UniValue heiradd(const UniValue& params, bool fHelp); +extern UniValue heirclaim(const UniValue& params, bool fHelp); +extern UniValue heirfundtokens(const UniValue& params, bool fHelp); +extern UniValue heiraddtokens(const UniValue& params, bool fHelp); +extern UniValue heirclaimtokens(const UniValue& params, bool fHelp); +extern UniValue heirinfo(const UniValue& params, bool fHelp); +extern UniValue heirlist(const UniValue& params, bool fHelp); extern UniValue channelsaddress(const UniValue& params, bool fHelp); extern UniValue oraclesaddress(const UniValue& params, bool fHelp); extern UniValue oracleslist(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0dcaaa848..b39a19668 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5417,27 +5417,145 @@ UniValue gatewaysaddress(const UniValue& params, bool fHelp) UniValue heiraddress(const UniValue& params, bool fHelp) { - struct CCcontract_info *cp,C; std::vector destPubkey; + /* + struct CCcontract_info *cp,C; std::vector pubkey; + cp = CCinit(&C,EVAL_HEIR); + if ( fHelp || params.size() > 1 ) + throw runtime_error("heiraddress [pubkey]\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + if ( params.size() == 1 ) + pubkey = ParseHex(params[0].get_str().c_str()); + return(CCaddress(cp,(char *)"Heir",pubkey)); + */ - cp = CCinit(&C,EVAL_HEIR); - if ( fHelp || (params.size() != 4 && params.size() != 3)) - throw runtime_error("heiraddress func txid amount [destpubkey]\n"); - if ( ensure_CCrequirements() < 0 ) - throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - //if ( params.size() == 1 ) - // pubkey = ParseHex(params[0].get_str().c_str()); - char funcid = ((char *)params[0].get_str().c_str())[0]; - uint256 assetid = Parseuint256((char *)params[1].get_str().c_str()); - int64_t funds = atof(params[2].get_str().c_str()) * COIN ; - if(params.size() == 4) - destPubkey = ParseHex(params[3].get_str().c_str()); + // make fake token tx: + struct CCcontract_info *cp, C; - //return HeirFundBad(funcid, assetid, funds, destPubkey); + if (fHelp || (params.size() < 1)) + throw runtime_error("heiraddress A|G|H|T|R assetid|destpubkey amountcoins [heirpubkey] [fundingtxid]\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - return(CCaddress(cp,(char *)"Heir",destPubkey)); + char badKind = ((char *)params[0].get_str().c_str())[0]; + + if (badKind == 'A') { + std::vector destPubkey; + if (params.size() == 2) { + cp = CCinit(&C, EVAL_HEIR); + destPubkey = ParseHex(params[1].get_str().c_str()); + return(CCaddress(cp, (char *)"Heir", destPubkey)); + } + else + return std::string("bad params for A"); + } + + CPubKey myPubkey = pubkey2pk(Mypubkey()); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());; + + if (badKind != 'R') { + + if (badKind == 'G' && params.size() != 3) + return std::string("incorrect params for G"); + if (badKind == 'H' && params.size() != 5) + return std::string("incorrect params for H, = 5"); + if (badKind == 'T' && params.size() != 3) + return std::string("incorrect params for T, = 3"); + + + uint256 assetid = Parseuint256((char *)params[1].get_str().c_str()); + int64_t amount = atof(params[2].get_str().c_str()) * COIN; + + uint256 fundingtxid; + CPubKey heirPubkey; + + if (badKind == 'H') { + + std::vector heirPubkeyStr = ParseHex(params[3].get_str().c_str()); + heirPubkey = pubkey2pk(heirPubkeyStr); + + fundingtxid = Parseuint256((char *)params[4].get_str().c_str()); + } + + + + int64_t txfee = 10000; + + uint8_t evalCodeInOpret = (badKind == 'H') ? EVAL_HEIR : EVAL_GATEWAYS; + cp = CCinit(&C, EVAL_ASSETS); + + int64_t normalInputs = AddNormalinputs(mtx, myPubkey, txfee + amount, 60); + // int64_t ccInputs = 0; + + + if (badKind == 'T') { + // just empty fake token + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, amount, myPubkey)); //note you need destPubkey for sending to gateways + } + else if (badKind == 'H') { + // heir add funding tx + mtx.vout.push_back(MakeCC1of2vout(EVAL_ASSETS, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk + } + else { // if (badKind == 'G') + CPubKey gatewayContractPubKey = GetUnspendable(cp, 0); + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(gatewayContractPubKey)) << OP_CHECKSIG)); + } + + int64_t change = (normalInputs - amount); + if (change != 0) { + mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG)); + } + std::cerr << "make fake token for contract=" << badKind << " added normalInputs=" << normalInputs << " change=" << change << std::endl; + + // note: it sets eval=EVAL_ASSETS in opreturn both for tokens and gateways cc addr + //script = EncodeAssetOpRet('t', assetid, zeroid, 0, (badKind == 'A' ? Mypubkey() : destPubkey)); // dimxy: are we sure about destPubkey here? it may be just pubkey of the author... + CScript opret; + assetid = revuint256(assetid); + fundingtxid = revuint256(fundingtxid); + if (badKind == 'T') + opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalCodeInOpret << (uint8_t)'t' << assetid ); + else if (badKind == 'H') + opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalCodeInOpret << (uint8_t)'t' << assetid << (uint8_t)'A' << myPubkey << heirPubkey << (int64_t)120 << fundingtxid); + else + opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalCodeInOpret << (uint8_t)'t' << assetid); // EVAL_GATEWAYS + + return(FinalizeCCTx(0, cp, mtx, myPubkey, txfee, opret)); // normal change added here + } + else + { + // move vout from user cc addr to gateways unspendable + CTransaction srctx; + + uint256 hashBlock; + const bool allowSlow = false; + uint256 srctxid = Parseuint256((char *)params[1].get_str().c_str()); + + struct CCcontract_info *cp, C; + cp = CCinit(&C, EVAL_GATEWAYS); + + uint64_t txfee = 10000; + CPubKey gatewayspk = GetUnspendable(cp, 0); + + if (myGetTransaction(srctxid, srctx, hashBlock) && srctx.vout.size() > 0) { + + int64_t normalInputs = AddNormalinputs(mtx, myPubkey, 2 * txfee, 4); + + mtx.vin.push_back(CTxIn(srctxid, 2, CScript())); // repaired src tx + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS, srctx.vout[2].nValue, gatewayspk)); + + CScript script = srctx.vout[srctx.vout.size() - 1].scriptPubKey; + + //mtx.fOverwintered = true; + + return(FinalizeCCTx(0, cp, mtx, myPubkey, txfee, script)); // normal change added here + } + } + return std::string("there has been some error"); } + + UniValue lottoaddress(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; std::vector pubkey; @@ -5518,17 +5636,30 @@ UniValue rewardsaddress(const UniValue& params, bool fHelp) return(CCaddress(cp,(char *)"Rewards",pubkey)); } +UniValue assetsaddress(const UniValue& params, bool fHelp) +{ + struct CCcontract_info *cp, C; std::vector pubkey; + cp = CCinit(&C, EVAL_ASSETS); + if (fHelp || params.size() > 1) + throw runtime_error("assetsaddress [pubkey]\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + if (params.size() == 1) + pubkey = ParseHex(params[0].get_str().c_str()); + return(CCaddress(cp, (char *)"Assets", pubkey)); +} + UniValue tokenaddress(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; std::vector pubkey; - cp = CCinit(&C,EVAL_ASSETS); + cp = CCinit(&C,EVAL_TOKENS); if ( fHelp || params.size() > 1 ) throw runtime_error("tokenaddress [pubkey]\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); if ( params.size() == 1 ) pubkey = ParseHex(params[0].get_str().c_str()); - return(CCaddress(cp,(char *)"Assets",pubkey)); + return(CCaddress(cp,(char *)"Tokens", pubkey)); } UniValue marmara_poolpayout(const UniValue& params, bool fHelp) @@ -6895,7 +7026,7 @@ UniValue tokencreate(const UniValue& params, bool fHelp) return(result); } } - hex = CreateAsset(0,supply,name,description); + hex = CreateToken(0,supply,name,description); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); @@ -6927,7 +7058,7 @@ UniValue tokentransfer(const UniValue& params, bool fHelp) ERR_RESULT("amount must be positive"); return(result); } - hex = AssetTransfer(0,tokenid,pubkey,amount); + hex = TokenTransfer(0,tokenid,pubkey,amount); if (amount > 0) { if ( hex.size() > 0 ) { @@ -6964,7 +7095,11 @@ UniValue tokenconvert(const UniValue& params, bool fHelp) ERR_RESULT("amount must be positive"); return(result); } - hex = AssetConvert(0,tokenid,pubkey,amount,evalcode); + + ERR_RESULT("deprecated"); + return(result); + +/* hex = AssetConvert(0,tokenid,pubkey,amount,evalcode); if (amount > 0) { if ( hex.size() > 0 ) { @@ -6974,7 +7109,7 @@ UniValue tokenconvert(const UniValue& params, bool fHelp) } else { ERR_RESULT("amount must be positive"); } - return(result); + return(result); */ } UniValue tokenbid(const UniValue& params, bool fHelp) @@ -7271,6 +7406,270 @@ UniValue getbalance64(const UniValue& params, bool fHelp) return ret; } +// heir contract functions for coins +UniValue heirfund(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); + //uint256 txid; + int64_t txfee; + int64_t amount; + int64_t inactivitytime; + std::string hex; + std::vector pubkey; + std::string name; + + //TODO: do we need this? + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 5) + throw runtime_error("heirfund fee funds heirname heirpubkey inactivitytime\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + + txfee = atof((char*)params[0].get_str().c_str()) * COIN; + amount = atof((char*)params[1].get_str().c_str()) * COIN; + name = params[2].get_str(); + pubkey = ParseHex(params[3].get_str().c_str()); + inactivitytime = atof((char*)params[4].get_str().c_str()); + + + hex = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, zeroid); + if (hex.size() > 0) { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } + else + ERR_RESULT("couldn't create heir fund"); + + return result; +} + + +UniValue heiradd(const UniValue& params, bool fHelp) +{ + UniValue result; // UniValue result(UniValue::VOBJ); + uint256 fundingtxid; + uint64_t txfee; + int64_t amount; + int64_t inactivitytime; + std::string hex; + std::vector pubkey; + std::string name; + + // TODO: do we need this? + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 3) + throw runtime_error("heiradd fee funds fundingtxid\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + + txfee = atof((char*)params[0].get_str().c_str()) * COIN; + amount = atof((char*)params[1].get_str().c_str()) * COIN; + fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); + + result = HeirAddCoinCaller(fundingtxid, txfee, amount); + /* if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldn't claim heir fund"); */ + + + return result; +} + +UniValue heirclaim(const UniValue& params, bool fHelp) +{ + UniValue result; // result(UniValue::VOBJ); + uint256 fundingtxid; + uint64_t txfee; + int64_t amount; + int64_t inactivitytime; + std::string hex; + std::vector pubkey; + std::string name; + + // do we need this? + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 3) + throw runtime_error("heirclaim fee funds fundingtxid\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + + txfee = atof((char*)params[0].get_str().c_str()) * COIN; + amount = atof((char*)params[1].get_str().c_str()) * COIN; + fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); + + result = HeirClaimCoinCaller(fundingtxid, txfee, amount); + /* if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldn't claim heir fund"); */ + + return result; +} + +// same heir contract functions for tokens +UniValue heirfundtokens(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); + uint256 assetid; + uint64_t txfee; + int64_t amount; + int64_t inactivitytime; + std::string hex; + std::vector pubkey; + std::string name; + + //TODO: do we need this (dimxy)? + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 6) + throw runtime_error("heirfundtokens fee funds heirname heirpubkey inactivitytime assetid\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + + txfee = atoll((char*)params[0].get_str().c_str()); + amount = atoll((char*)params[1].get_str().c_str()); + name = params[2].get_str(); + pubkey = ParseHex(params[3].get_str().c_str()); + inactivitytime = atof((char*)params[4].get_str().c_str()); + assetid = Parseuint256((char*)params[5].get_str().c_str()); + + + hex = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, assetid); + if (hex.size() > 0) { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } + else + ERR_RESULT("couldn't create heir fund"); + + + return result; +} + + +UniValue heiraddtokens(const UniValue& params, bool fHelp) +{ + UniValue result; // UniValue result(UniValue::VOBJ); + uint256 fundingtxid; + uint64_t txfee; + int64_t amount; + int64_t inactivitytime; + std::string hex; + std::vector pubkey; + std::string name; + + // TODO: do we need this? + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 3) + throw runtime_error("heiraddtokens fee funds fundingtxid\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + + txfee = atoll((char*)params[0].get_str().c_str()); + amount = atoll((char*)params[1].get_str().c_str()); + fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); + + result = HeirAddTokenCaller(fundingtxid, txfee, amount); + /* if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldn't claim heir fund"); */ + + + return result; +} + +UniValue heirclaimtokens(const UniValue& params, bool fHelp) +{ + UniValue result; // result(UniValue::VOBJ); + uint256 fundingtxid; + int64_t txfee; + int64_t amount; + int64_t inactivitytime; + std::string hex; + std::vector pubkey; + std::string name; + + // do we need this? + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() != 3) + throw runtime_error("heirclaimtokens fee funds fundingtxid\n"); + if (ensure_CCrequirements() < 0) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + + txfee = atoll((char*)params[0].get_str().c_str()); + amount = atoll((char*)params[1].get_str().c_str()); + fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); + + result = HeirClaimTokenCaller(fundingtxid, txfee, amount); + /* if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else ERR_RESULT("couldn't claim heir fund"); */ + + return result; +} + +UniValue heirinfo(const UniValue& params, bool fHelp) +{ + uint256 fundingtxid; + if (fHelp || params.size() != 1) // or 0? + throw runtime_error("heirinfo fundingtxid\n"); + // if ( ensure_CCrequirements() < 0 ) + // throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + fundingtxid = Parseuint256((char*)params[0].get_str().c_str()); + return (HeirInfo(fundingtxid)); +} + +UniValue heirlist(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 0) // or 0? + throw runtime_error("heirlist\n"); + + // if ( ensure_CCrequirements() < 0 ) + // throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + + return (HeirList()); +} + + + + extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp extern UniValue importprivkey(const UniValue& params, bool fHelp); extern UniValue importaddress(const UniValue& params, bool fHelp); From be71d108b296df1a6ac540af90bee4996a3d947f Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 7 Jan 2019 23:21:57 +0500 Subject: [PATCH 002/106] Added CCaddr1of2set and FinalizeCCtx modified to support it (small test CCerror code added - temp) --- src/cc/CCassetstx.cpp | 65 +++++++++++++++++++++++----------------- src/cc/CCinclude.h | 28 +++++++++++++---- src/cc/CCtx.cpp | 24 +++++++++++---- src/cc/CCutils.cpp | 8 +++++ src/cc/heir.cpp | 9 +++--- src/wallet/rpcwallet.cpp | 8 +++++ 6 files changed, 100 insertions(+), 42 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index cae4b42bb..17c16bd6a 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -393,7 +393,7 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p uint64_t mask; int64_t inputs, CCchange; CScript opret; - struct CCcontract_info *cp,C; + struct CCcontract_info *cpTokens,C; //std::cerr << "CreateSell() askamount=" << askamount << " pricetotal=" << pricetotal << std::endl; @@ -402,16 +402,16 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p return(""); } - cp = CCinit(&C, EVAL_TOKENS); // NOTE: tokens is here + cpTokens = CCinit(&C, EVAL_TOKENS); // NOTE: tokens is here - if ( txfee == 0 ) + if (txfee == 0) txfee = 10000; mypk = pubkey2pk(Mypubkey()); if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); - if ((inputs = AddTokenCCInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0) + if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60)) > 0) { if (inputs < askamount) { //was: askamount = inputs; @@ -420,14 +420,14 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p return (""); } - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,askamount, GetUnspendable(cp,0))); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,askamount, GetUnspendable(cpTokens,0))); if (inputs > askamount) CCchange = (inputs - askamount); if (CCchange != 0) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, Mypubkey()); - return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret)); + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,opret)); } else { fprintf(stderr, "need some tokens to place ask\n"); @@ -439,6 +439,7 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p return(""); } +////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -497,7 +498,7 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a } return(""); -} +} ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// // unlocks coins std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) @@ -508,11 +509,11 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) uint256 hashBlock; int64_t bidamount; CPubKey mypk; - struct CCcontract_info *cp,C; + struct CCcontract_info *cpAssets, C; - cp = CCinit(&C, EVAL_ASSETS); + cpAssets = CCinit(&C, EVAL_ASSETS); - if ( txfee == 0 ) + if (txfee == 0) txfee = 10000; mypk = pubkey2pk(Mypubkey()); @@ -525,7 +526,7 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) bidamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, Mypubkey()))); + return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, Mypubkey()))); } } return(""); @@ -536,11 +537,11 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; - struct CCcontract_info *cp,C; + struct CCcontract_info *cpTokens, C; - cp = CCinit(&C, EVAL_TOKENS); + cpTokens = CCinit(&C, EVAL_TOKENS); - if ( txfee == 0 ) + if (txfee == 0) txfee = 10000; mypk = pubkey2pk(Mypubkey()); @@ -553,7 +554,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) askamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); - return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, Mypubkey()))); + return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, Mypubkey()))); } } return(""); @@ -570,16 +571,18 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f int32_t bidvout=0; uint64_t mask; int64_t origprice, bidamount, paid_amount, remaining_required, inputs, CCchange=0; - struct CCcontract_info *cp,C; + struct CCcontract_info *cpTokens, tokensC; + struct CCcontract_info *cpAssets, assetsC; if (fillamount < 0) { fprintf(stderr,"negative fillamount %lld\n", (long long)fillamount); return(""); } - cp = CCinit(&C, EVAL_TOKENS); + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + cpAssets = CCinit(&assetsC, EVAL_ASSETS); - if ( txfee == 0 ) + if (txfee == 0) txfee = 10000; mypk = pubkey2pk(Mypubkey()); @@ -594,7 +597,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); - if ((inputs = AddTokenCCInputs(cp, mtx, mypk, assetid, fillamount, 60)) > 0) + if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60)) > 0) { if (inputs < fillamount) { std::cerr << "FillBuyOffer(): insufficient tokens to fill buy offer" << std::endl; @@ -607,16 +610,24 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f if (inputs > fillamount) CCchange = (inputs - fillamount); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, bidamount - paid_amount, GetUnspendable(cp,0))); // tokens + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, bidamount - paid_amount, GetUnspendable(cpTokens, NULL))); // tokens mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, fillamount, pubkey2pk(origpubkey))); // coins + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, fillamount, pubkey2pk(origpubkey))); // coins on assets if (CCchange != 0) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins on assets fprintf(stderr,"remaining %llu -> origpubkey\n", (long long)remaining_required); - return(FinalizeCCTx(mask,cp,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, origpubkey))); + // add additional unspendable addr from Assets: + char unspendableAssetsAddr[64]; + uint8_t unspendableAssetsPrivkey[32]; + + CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); + GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); + CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); + + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, origpubkey))); } else return("dont have any assets to fill bid\n"); } } @@ -694,16 +705,16 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt if (assetid2 != zeroid && inputs > paid_nValue) CCchange = (inputs - paid_nValue); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // coins + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // coins in Assets cc addr mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); // tokens if (assetid2 != zeroid) - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); // tokens (not implemented correctly) + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); // tokens... (swap is not implemented yet) else - mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); // coins + mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); // coins normal if (CCchange != 0) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins in Assets cc addr return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, origpubkey))); } else { diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 56c4b27d5..ec1557e2b 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -86,12 +86,27 @@ struct CC_meta struct CCcontract_info { - char unspendableCCaddr[64],CChexstr[72],normaladdr[64],unspendableaddr2[64],unspendableaddr3[64]; - uint8_t CCpriv[32],unspendablepriv2[32],unspendablepriv3[32]; - CPubKey unspendablepk2,unspendablepk3; - bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn); - bool (*ismyvin)(CScript const& scriptSig); - uint8_t evalcode,evalcode2,evalcode3,didinit; + // this is for spending from 'unspendable' CC address + uint8_t evalcode; + char unspendableCCaddr[64], CChexstr[72], normaladdr[64]; + uint8_t CCpriv[32]; + + // this for 1of2 key spending condition (for this evalcode) + // NOTE: only one evalcode is allowed at this time + char unspendable1of2addr[64]; + CPubKey unspendable1of2pk[2]; + + // this is for spending from two additional 'unspendable' CC addresses of other eval codes + // (that is, for spending from several cc contract 'unspendable' addresses): + uint8_t evalcode2, evalcode3; + char unspendableaddr2[64], unspendableaddr3[64]; + uint8_t unspendablepriv2[32], unspendablepriv3[32]; + CPubKey unspendablepk2, unspendablepk3; + + bool (*validate)(struct CCcontract_info *cp, Eval* eval, const CTransaction &tx, uint32_t nIn); // cc contract tx validation callback + bool (*ismyvin)(CScript const& scriptSig); // checks if evalcode is present in the scriptSig param + + uint8_t didinit; }; struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode); @@ -164,6 +179,7 @@ CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2); CC* GetCryptoCondition(CScript const& scriptSig); void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); +void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr); bool IsCCInput(CScript const& scriptSig); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 57a2a327b..dc8b4788e 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -44,7 +44,10 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; - uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*othercond3=0,*cond; CPubKey unspendablepk; + uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; + CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *cond; + CPubKey unspendablepk; + n = mtx.vout.size(); for (i=0; iunspendableaddr2) == 0) { //fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2); privkey = cp->unspendablepriv2; - if ( othercond2 == 0 && cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR && cp->evalcode != EVAL_ASSETS && cp->evalcode != EVAL_TOKENS) - othercond2 = MakeCCcond1(cp->evalcode2,cp->unspendablepk2); - else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR || cp->evalcode == EVAL_ASSETS || cp->evalcode == EVAL_TOKENS) ) - othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3); + if ( othercond2 == 0 ) //&& cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR && cp->evalcode != EVAL_ASSETS && cp->evalcode != EVAL_TOKENS) + othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2); + //else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR || cp->evalcode == EVAL_ASSETS || cp->evalcode == EVAL_TOKENS) ) + // othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3); cond = othercond2; } + // check if this is 3rd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 ) { //fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3); @@ -158,6 +163,15 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3); cond = othercond3; } + // check if this is spending from 1of2 cc addr: + else if (strcmp(cp->unspendable1of2addr, destaddr) == 0) + { + //fprintf(stderr,"matched %s unspendable1of2!\n",cp->unspendable1of2addr); + privkey = myprivkey; + if (othercond1of2 == 0) + othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->unspendable1of2pk[0], cp->unspendable1of2pk[1]); + cond = othercond1of2; + } else { fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index ed16805d7..c0fea0c9f 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -195,6 +195,14 @@ void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t * strcpy(cp->unspendableaddr3,coinaddr); } +// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 cryptocondition vout: +void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr) +{ + cp->unspendable1of2pk[0] = pk1; + cp->unspendable1of2pk[1] = pk2; + strcpy(cp->unspendable1of2addr, coinaddr); +} + bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) { CTxDestination address; txnouttype whichType; diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 81318ad1e..90557d7ac 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -1061,11 +1061,12 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); Myprivkey(myprivkey); - //fprintf(stderr,"HeirClaim() before setting unspendable CC addr2= (%s) addr3= (%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); - CCaddr2set(cp, Helper::getMyEval(), ownerPubkey, myprivkey, coinaddr); - CCaddr3set(cp, Helper::getMyEval(), heirPubkey, myprivkey, coinaddr); + ////fprintf(stderr,"HeirClaim() before setting unspendable CC addr2= (%s) addr3= (%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); + //CCaddr2set(cp, Helper::getMyEval(), ownerPubkey, myprivkey, coinaddr); + //CCaddr3set(cp, Helper::getMyEval(), heirPubkey, myprivkey, coinaddr); + ////fprintf(stderr, "HeirClaim() after setting unspendable CC addr2=(%s) addr3=(%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); - fprintf(stderr, "HeirClaim() after setting unspendable CC addr2=(%s) addr3=(%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); + CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr); // add opreturn 'C' and sign tx: // this txfee will be ignored std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b39a19668..1320da61c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6952,12 +6952,20 @@ UniValue tokenlist(const UniValue& params, bool fHelp) UniValue tokeninfo(const UniValue& params, bool fHelp) { +#ifdef TESTMODE + std::cerr << "is CCerror clear? CCerror=" << CCerror << std::endl; +#endif uint256 tokenid; if ( fHelp || params.size() != 1 ) throw runtime_error("tokeninfo tokenid\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); tokenid = Parseuint256((char *)params[0].get_str().c_str()); + +#ifdef TESTMODE + CCerror = "test error"; +#endif + return(AssetInfo(tokenid)); } From 675787d67658245c64c795433a28816b9a0e2552 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 7 Jan 2019 23:24:13 +0500 Subject: [PATCH 003/106] Asset contract modified to support the Tokens contract --- src/cc/CCassetsCore.cpp | 100 +++++++++++++++++------------- src/cc/CCassetstx.cpp | 113 ++++++++++++++++++++++------------ src/cc/CCinclude.h | 6 +- src/cc/CCtokens.cpp | 132 ++++++++++++++++++++++++++++++++-------- src/cc/CCtokens.h | 4 +- src/cc/CCtx.cpp | 3 +- src/cc/CCutils.cpp | 8 +-- src/cc/assets.cpp | 52 +++++++++------- src/cc/prices.cpp | 4 +- src/script/script.cpp | 14 +++++ src/script/script.h | 2 + 11 files changed, 303 insertions(+), 135 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 52c73d47f..837c4361e 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -239,25 +239,28 @@ CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,st } */ -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector origpubkey) +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey) { CScript opret; uint8_t evalcode = EVAL_ASSETS; uint8_t funcId = (uint8_t)'t'; + uint8_t ccType = 0; + if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) + ccType = voutPubkeys.size(); tokenid = revuint256(tokenid); switch ( assetFuncId ) { //case 't': this cannot be here case 'x': case 'o': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId); break; case 's': case 'b': case 'S': case 'B': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId << price << origpubkey); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId << price << origpubkey); break; case 'E': case 'e': assetid2 = revuint256(assetid2); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << assetFuncId << assetid2 << price << origpubkey); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId << assetid2 << price << origpubkey); break; default: fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId); @@ -283,33 +286,38 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &o uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey) { - std::vector vopret; - uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyFuncId; + std::vector vopretExtra; + uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId; uint256 dummyTokenid; - - GetOpReturnData(scriptPubKey, vopret); - - script = (uint8_t *)vopret.data(); - if (script == 0) { - std::cerr << "DecodeAssetOpRet() script is empty" << std::endl; - return (uint8_t)0; - } + std::vector voutPubkeysDummy; tokenid = zeroid; assetid2 = zeroid; price = 0; - bool isEof = true; // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! - bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof()); + // First - decode token opret: + funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra); - if (!result && isEof) { // NOTE: 'result==false' means 'parse error' OR 'not eof state'. Consequently, 'result==false' but 'isEof==true' means just 'parse error' - std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << std::endl; + + /*GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if (script == 0) { + std::cerr << "DecodeAssetOpRet() script is empty" << std::endl; + return (uint8_t)0; + }*/ + //bool isEof = true; // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! + //bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof()); + + if (funcId == 0 || vopretExtra.size() == 0) { + std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretExtra.size()=" << vopretExtra.size() << std::endl; return (uint8_t)0; } - tokenid = revuint256(tokenid); + ////tokenid = revuint256(tokenid); already done in DecodeToken! - std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl; + assetFuncId = vopretExtra.begin()[0]; + + //std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl; if(evalCodeInOpret == EVAL_ASSETS) { @@ -328,20 +336,20 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, break; */ case 'x': case 'o': - if (isEof) // no data after 'assetFuncId' allowed + if (vopretExtra.size() == 1) // no data after 'assetFuncId' allowed { return(assetFuncId); } break; case 's': case 'b': case 'S': case 'B': - if (E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> dummyTokenid; ss >> dummyFuncId; ss >> price; ss >> origpubkey) != 0) + if (E_UNMARSHAL(vopretExtra, ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0) { //fprintf(stderr,"got price %llu\n",(long long)price); return(assetFuncId); } break; case 'E': case 'e': - if ( E_UNMARSHAL(vopret,ss >> dummyEvalCode; ss >> dummyFuncId; ss >> dummyTokenid; ss >> dummyFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) + if ( E_UNMARSHAL(vopretExtra, ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) { //fprintf(stderr,"got price %llu\n",(long long)price); assetid2 = revuint256(assetid2); @@ -349,34 +357,37 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, } break; default: - fprintf(stderr,"DecodeAssetOpRet: illegal funcid.%02x\n", funcId); - funcId = 0; + fprintf(stderr,"DecodeAssetOpRet: illegal assetFuncId.%02x\n", assetFuncId); + //funcId = 0; break; } } - return(funcId); + return (uint8_t)0; } bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CTransaction &tx) { uint256 assetid,assetid2; uint8_t evalCode; - if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey) != 0 ) + if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey) != 0 ) return(true); - else return(false); + else + return(false); } bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx) { - uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector origpubkey; CScript script; + uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector origpubkey; + CScript script; uint8_t evalCode; n = tx.vout.size(); if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey)) == 0 ) return(false); - if ( GetCCaddress(cp,CCaddr,pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr,CScript() << origpubkey << OP_CHECKSIG) != 0 ) + if ( GetCCaddress(cp, CCaddr, pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG) != 0 ) return(true); - else return(false); + else + return(false); } @@ -398,7 +409,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch } else if ( Getscriptaddress(destaddr,vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 ) { - fprintf(stderr,"%s vs %s\n",destaddr,(char *)cp->unspendableCCaddr); + fprintf(stderr,"AssetValidateCCvin cc addr %s is not evalcode 0x%02x unspendable %s\n", destaddr, (int)cp->evalcode, (char *)cp->unspendableCCaddr); return eval->Invalid("invalid vin AssetsCCaddr"); } //else if ( vinTx.vout[0].nValue < 10000 ) @@ -415,6 +426,8 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr { CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode; CCaddr[0] = origaddr[0] = 0; + + // validate locked coins on Assets vin[1] if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 ) return(0); else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) @@ -441,7 +454,8 @@ int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpp return(0); if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey,vinTx,0,assetid)) == 0 ) return eval->Invalid("invalid missing CC vout0 for sellvin"); - else return(assetoshis); + else + return(assetoshis); } @@ -475,9 +489,8 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr return(true); } } */ - // TODO: hope this was unneeded!!! (dimxy) - else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset - return(false); + //else if ((funcid == 'b' || funcid == 'B') && v == 0) // critical! 'b'/'B' vout0 is NOT asset + // return(false); else if (funcid != 'E') { if (assetid != zeroid && assetidOpret == assetid) @@ -542,8 +555,8 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_ cpTokens = CCinit(&C, EVAL_TOKENS); for (int32_t i = 0; iismyvin)(tx.vin[i].scriptSig) || (*cpTokens->ismyvin)(tx.vin[i].scriptSig)) // || IsVinAllowed(tx.vin[i].scriptSig) != 0) + { // only tokens are relevant!! + if (/*(*cpAssets->ismyvin)(tx.vin[i].scriptSig)*/ (*cpTokens->ismyvin)(tx.vin[i].scriptSig) ) // || IsVinAllowed(tx.vin[i].scriptSig) != 0) { //std::cerr << indentStr << "AssetExactAmounts() eval is true=" << (eval != NULL) << " ismyvin=ok for_i=" << i << std::endl; // we are not inside the validation code -- dimxy @@ -555,7 +568,10 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_ else { // validate vouts of vintx //std::cerr << indentStr << "AssetExactAmounts() check vin i=" << i << " nValue=" << vinTx.vout[tx.vin[i].prevout.n].nValue << std::endl; - assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, vinTx, tx.vin[i].prevout.n, assetid); + //assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, vinTx, tx.vin[i].prevout.n, assetid); + std::vector vopretExtra; + std::vector vinPubkeysEmpty; + assetoshis = IsTokensvout(false, false, cpTokens, NULL, vopretExtra, vinTx, tx.vin[i].prevout.n, assetid, vinPubkeysEmpty); if (assetoshis != 0) { std::cerr << "AssetExactAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl; @@ -585,9 +601,11 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_ } } - //std::cerr << "AssetExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; + std::cerr << "AssetExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; - /* if (inputs != outputs) { + /* we do not verify inputs == outputs here, + it's done in Tokens: + if (inputs != outputs) { if (tx.GetHash() != assetid) { std::cerr << "AssetExactAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; return (!eval) ? false : eval->Invalid("assets cc inputs != cc outputs"); diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 17c16bd6a..fe86d58de 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -145,11 +145,11 @@ UniValue AssetOrders(uint256 refassetid) char numstr[32], funcidstr[16], origaddr[64], assetidstr[65]; txid = it->first.txhash; - //std::cerr << "addOrders txid" << txid.GetHex() << std::endl; + //std::cerr << "addOrders() txid=" << txid.GetHex() << std::endl; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey); - //std::cerr << "addOrders vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << std::endl; + //std::cerr << "addOrders() vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl; if (vintx.vout.size() > 0 && (funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0) { if (refassetid != zero && assetid != refassetid) @@ -163,6 +163,8 @@ UniValue AssetOrders(uint256 refassetid) //fprintf(stderr," refassetid\n"); return; } + + //std::cerr << "addOrders() it->first.index=" << it->first.index << " vintx.vout[it->first.index].nValue=" << vintx.vout[it->first.index].nValue << std::endl; if (vintx.vout[it->first.index].nValue == 0) return; @@ -213,7 +215,7 @@ UniValue AssetOrders(uint256 refassetid) } } result.push_back(item); - //fprintf(stderr,"func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN); + //fprintf(stderr,"addOrders() func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN); } } }; @@ -378,8 +380,12 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in return (""); } - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, GetUnspendable(cpAssets,0))); - return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, Mypubkey()))); + CPubKey unspendablePubkey = GetUnspendable(cpAssets, 0); + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendablePubkey)); + + std::vector voutTokenPubkeys; // should be empty - no token vouts + + return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()))); } CCerror = strprintf("no coins found to make buy offer"); return(""); @@ -420,13 +426,17 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p return (""); } - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,askamount, GetUnspendable(cpTokens,0))); + CPubKey unspendablePubkey = GetUnspendable(cpTokens, 0); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, unspendablePubkey)); if (inputs > askamount) CCchange = (inputs - askamount); if (CCchange != 0) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); - opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, Mypubkey()); + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(unspendablePubkey); + + opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,opret)); } else { @@ -474,18 +484,22 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a return (""); } - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, GetUnspendable(cp, 0))); + CPubKey unspendablePubkey = GetUnspendable(cp, 0); + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, unspendablePubkey)); if (inputs > askamount) CCchange = (inputs - askamount); if (CCchange != 0) mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); - if (assetid2 == zeroid) - opret = EncodeAssetOpRet('s', assetid, zeroid, pricetotal, Mypubkey()); - else - { - opret = EncodeAssetOpRet('e', assetid, assetid2, pricetotal, Mypubkey()); + + std::vector voutTokenPubkeys; // should be empty - no token vouts + + if (assetid2 == zeroid) { + opret = EncodeAssetOpRet('s', assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); + } + else { + opret = EncodeAssetOpRet('e', assetid, assetid2, pricetotal, voutTokenPubkeys, Mypubkey()); } return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret)); } @@ -524,9 +538,12 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0) { bidamount = vintx.vout[0].nValue; - mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); + mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, Mypubkey()))); + + std::vector voutTokenPubkeys; // should be empty, no tokens vout + + return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey()))); } } return(""); @@ -554,7 +571,11 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) askamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); - return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, Mypubkey()))); + + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(mypk); + + return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey()))); } } return(""); @@ -595,7 +616,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f bidamount = vintx.vout[bidvout].nValue; SetAssetOrigpubkey(origpubkey, origprice, vintx); - mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); + mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); // Coins on Assets unspendable if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60)) > 0) { @@ -610,25 +631,30 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f if (inputs > fillamount) CCchange = (inputs - fillamount); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, bidamount - paid_amount, GetUnspendable(cpTokens, NULL))); // tokens - mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, fillamount, pubkey2pk(origpubkey))); // coins on assets + CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); + uint8_t unspendableAssetsPrivkey[32]; + CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); + + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // 0 coins remainder + mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // 1 coins to normal + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // 2 tokens paid if (CCchange != 0) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins on assets + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // 3 change in tokens fprintf(stderr,"remaining %llu -> origpubkey\n", (long long)remaining_required); - // add additional unspendable addr from Assets: char unspendableAssetsAddr[64]; - uint8_t unspendableAssetsPrivkey[32]; - - CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); + // add additional unspendable addr from Assets: CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); - return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, origpubkey))); - } else return("dont have any assets to fill bid\n"); + // token vout verification pubkeys: + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(unspendableTokensPk); + + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, voutTokenPubkeys, origpubkey))); + } else return("dont have any assets to fill bid"); } } return("no normal coins left"); @@ -683,7 +709,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx! if (assetid2 != zeroid) - inputs = AddAssetInputs(cpTokens, mtx, mypk, assetid2, paid_nValue, 60); + inputs = AddAssetInputs(cpTokens, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet else { inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60); @@ -698,25 +724,36 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt } if (assetid2 != zeroid) - SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); + SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); //not implemented correctly yet else SetAskFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); if (assetid2 != zeroid && inputs > paid_nValue) CCchange = (inputs - paid_nValue); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // coins in Assets cc addr - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); // tokens + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, orig_assetoshis - received_assetoshis, GetUnspendable(cpTokens, NULL))); // 0 tokens cc addr - ask remainder + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //1 tokens to self - if (assetid2 != zeroid) - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); // tokens... (swap is not implemented yet) - else - mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); // coins normal + if (assetid2 != zeroid) { + std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl; + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //2 tokens... (swap is not implemented yet) + } + else { + //std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl; + mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //2 coins normal to whom who asked token + } - if (CCchange != 0) - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); // coins in Assets cc addr + // not implemented + if (CCchange != 0) { + std::cerr << "FillSell() WARNING: asset swap not implemented yet! (CCchange)" << std::endl; + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //3 coins in Assets cc addr + } - return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, origpubkey))); + // vout verification pubkeys: + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(mypk); + + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, voutTokenPubkeys, origpubkey))); } else { CCerror = strprintf("filltx not enough utxos"); fprintf(stderr,"%s\n", CCerror.c_str()); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index ec1557e2b..1b6e804fc 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -151,13 +151,15 @@ uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk); //int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); +int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); + bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector origpubkey); +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); -uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &vopretExtra); +uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra); //uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey); uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index c85297ddb..d9e689f85 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -76,11 +76,12 @@ uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector return (uint8_t)0; } -uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &vopretExtra) +uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra) { std::vector vopret, extra, dummyPubkey; - uint8_t funcid=0, *script, e, dummyFuncId; + uint8_t funcId=0, *script, dummyEvalCode, dummyFuncId, ccType; std::string dummyName; std::string dummyDescription; + CPubKey voutPubkey1, voutPubkey2; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); @@ -88,28 +89,45 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 if (script != 0 /*enable all evals: && script[0] == EVAL_TOKENS*/) { + // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! bool isEof = true; + evalCode = script[0]; - funcid = script[1]; - //fprintf(stderr,"decode.[%c]\n",funcid); - switch ( funcid ) + funcId = script[1]; + //fprintf(stderr,"decode.[%c]\n",funcId); + + switch ( funcId ) { case 'c': return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription); //break; case 't': //not used yet: case 'l': - if (E_UNMARSHAL(vopret, ss >> e; ss >> dummyFuncId; ss >> tokenid; isEof = ss.eof(); vopretExtra = std::vector(ss.begin(), ss.end())) || !isEof) + // NOTE: 'E_UNMARSHAL result==false' means 'parse error' OR 'not eof state'. Consequently, 'result==false' but 'isEof==true' means just 'parse error' + if (E_UNMARSHAL(vopret, ss >> dummyEvalCode; ss >> dummyFuncId; ss >> tokenid; ss >> ccType; if (ccType >= 1) ss >> voutPubkey1; if (ccType == 2) ss >> voutPubkey2; isEof = ss.eof(); vopretExtra = std::vector(ss.begin(), ss.end())) + || !isEof) { + + if (!(ccType >= 0 && ccType <= 2)) { //incorrect ccType + std::cerr << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << std::endl; + return (uint8_t)0; + } + + // add verification pubkeys: + voutPubkeys.clear(); + if (voutPubkey1.IsValid()) + voutPubkeys.push_back(voutPubkey1); + if (voutPubkey2.IsValid()) + voutPubkeys.push_back(voutPubkey2); + tokenid = revuint256(tokenid); - return(funcid); + return(funcId); } - std::cerr << "DecodeTokenOpRet() isEof=" << isEof << std::endl; - fprintf(stderr, "DecodeTokenOpRet() bad opret format\n"); // this may be just check, no error logging + std::cerr << "DecodeTokenOpRet() warning: bad opret format, isEof=" << isEof << " ccType=" << ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl; return (uint8_t)0; default: - fprintf(stderr, "DecodeTokenOpRet() illegal funcid.%02x\n", funcid); + std::cerr << "DecodeTokenOpRet() illegal funcid=" << (int)funcId << std::endl; return (uint8_t)0; } } @@ -124,16 +142,18 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & static uint256 zero; CTxDestination address; CTransaction vinTx, createTx; uint256 hashBlock, tokenid, tokenid2; int32_t i, starti, numvins, numvouts, preventCCvins, preventCCvouts; - int64_t remaining_price, nValue, tokenoshis, outputs, inputs, tmpprice, totalunits, ignore; std::vector origpubkey, tmporigpubkey, ignorepubkey; + int64_t remaining_price, nValue, tokenoshis, outputs, inputs, tmpprice, totalunits, ignore; + std::vector vopretExtra, tmporigpubkey, ignorepubkey; uint8_t funcid, evalCodeInOpret; char destaddr[64], origaddr[64], CCaddr[64]; + std::vector voutTokenPubkeys; numvins = tx.vin.size(); numvouts = tx.vout.size(); outputs = inputs = 0; preventCCvins = preventCCvouts = -1; - if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, origpubkey)) == 0) + if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, vopretExtra)) == 0) return eval->Invalid("TokenValidate: invalid opreturn payload"); fprintf(stderr, "TokensValidate (%c)\n", funcid); @@ -206,7 +226,7 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & thread_local uint32_t tokenValIndentSize = 0; // validates opret for token tx: -bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector &vopretExtra) { +bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector &voutPubkeys, std::vector &vopretExtra) { uint256 tokenidOpret, tokenidOpret2; uint8_t funcid, evalCode; @@ -216,7 +236,7 @@ bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector int32_t n = tx.vout.size(); - if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, tokenidOpret, vopretExtra)) == 0) + if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, tokenidOpret, voutPubkeys, vopretExtra)) == 0) { std::cerr << indentStr << "ValidateTokenOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl; return(false); @@ -241,18 +261,20 @@ bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector } + // Checks if the vout is a really Tokens CC vout // compareTotals == true, the func also validates the passed transaction itself: // it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx -int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, std::vector &vopretExtra, const CTransaction& tx, int32_t v, uint256 reftokenid) +int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &vopretExtra, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys) { // this is just for log messages indentation fur debugging recursive calls: std::string indentStr = std::string().append(tokenValIndentSize, '.'); //std::cerr << indentStr << "IsTokensvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for tokenid=" << reftokenid.GetHex() << std::endl; + //TODO: validate cc vouts are EVAL_TOKENS! - if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here + if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition()) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here { int32_t n = tx.vout.size(); // just check boundaries: @@ -261,7 +283,7 @@ int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, return(0); } - if (compareTotals) { + if (goDeeper) { //std::cerr << indentStr << "IsTokensvout() maxTokenExactAmountDepth=" << maxTokenExactAmountDepth << std::endl; //validate all tx int64_t myCCVinsAmount = 0, myCCVoutsAmount = 0; @@ -282,11 +304,41 @@ int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, } // moved opret checking to this new reusable func (dimxy): - const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, vopretExtra); + std::vector voutPubkeys; + const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, 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, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; - return tx.vout[v].nValue; + //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 (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { + CTxOut testVout; + if (voutPubkeys.size() == 1) + testVout = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]); + else // voutPubkeys.size() == 2 + testVout = MakeCC1of2vout(EVAL_TOKENS, 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; + return tx.vout[v].nValue; + } + } + + // maybe it is change? + for(std::vector::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) { + CTxOut testVout = MakeCC1vout(EVAL_TOKENS, 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; + return tx.vout[v].nValue; + } + } + } + else { + return tx.vout[v].nValue; + } } //std::cerr << indentStr; fprintf(stderr,"IsTokensvout() CC vout v.%d of n=%d amount=%.8f txid=%s\n",v,n,(double)0/COIN, tx.GetHash().GetHex().c_str()); @@ -296,9 +348,12 @@ int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, } // compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs) -bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid) +bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid) { 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(); inputs = outputs = 0; @@ -310,6 +365,33 @@ bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, in { // check for additional contracts which may send tokens to the Tokens contract if ((*cpTokens->ismyvin)(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))) @@ -322,7 +404,7 @@ bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, in 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(compareTotals, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid); + tokenoshis = IsTokensvout(goDeeper, false/*<--do not have pubkeys*/, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeysEmpty); tokenValIndentSize--; if (tokenoshis != 0) { @@ -339,7 +421,7 @@ bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, in tokenValIndentSize++; // Note: we pass in here 'false' because we don't need to call TokenExactAmounts() recursively from IsTokenvout // indeed, in this case we'll be checking this tx again - tokenoshis = IsTokensvout(false, cpTokens, eval, tmporigpubkey, tx, i, tokenid); + tokenoshis = IsTokensvout(false, true /*<--exclude non-tokens vouts*/, cpTokens, eval, tmporigpubkey, tx, i, tokenid, vinPubkeys); tokenValIndentSize--; if (tokenoshis != 0) @@ -393,7 +475,9 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C 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); - if ((nValue = IsTokensvout(true, cp, NULL, vopretExtra, vintx, vout, tokenid)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) + + std::vector vinPubkeysEmpty; + if ((nValue = IsTokensvout(true, false, cp, NULL, vopretExtra, vintx, vout, tokenid, vinPubkeysEmpty)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) { if (total != 0 && maxinputs != 0) mtx.vin.push_back(CTxIn(txid, vout, CScript())); diff --git a/src/cc/CCtokens.h b/src/cc/CCtokens.h index 2dc9a8e56..8ecbc1094 100644 --- a/src/cc/CCtokens.h +++ b/src/cc/CCtokens.h @@ -27,8 +27,8 @@ // CCcustom bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); -bool TokensExactAmounts(bool compareTotals, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid); -int64_t IsTokensvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid); +bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid); +//int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description); std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index dc8b4788e..3d95d0f17 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -333,7 +333,8 @@ int64_t CCtoken_balance(char *coinaddr,uint256 tokenid) if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN); - if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, vopretExtra) != 0 && assetid == tokenid ) + std::vector voutTokenPubkeys; + if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, voutTokenPubkeys, vopretExtra) != 0 && assetid == tokenid ) { sum += it->second.satoshis; } diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index c0fea0c9f..eef21c72a 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -307,17 +307,17 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK return(destaddr[0] != 0); } -bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue) +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); + 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) ) + else if ( cmpaddr != 0 && (Getscriptaddress(destaddr, vout.scriptPubKey) == 0 || strcmp(destaddr, cmpaddr) != 0) ) { - fprintf(stderr,"constrain vout error addr %s vs %s\n",cmpaddr!=0?cmpaddr:"",destaddr!=0?destaddr:""); + fprintf(stderr,"constrain vout error addr %s vs %s\n", cmpaddr!=0?cmpaddr:"", destaddr!=0?destaddr:""); return(false); } else if ( nValue != 0 && nValue != vout.nValue ) //(nValue == 0 && vout.nValue < 10000) || ( diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 47b9488c8..3a62a526a 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -140,12 +140,16 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid, evalCodeInOpret; - char destaddr[64],origaddr[64],CCaddr[64]; + char destaddr[64], origaddr[64], assetsCCaddr[64], tokensCCaddr[64]; // we need this for validating tokens' vins/vous: struct CCcontract_info *cpTokens, tokensC; cpTokens = CCinit(&tokensC, EVAL_TOKENS); + //CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); + //CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, NULL); + //GetCCaddress(cpTokens, tokensUnspendableCCaddr, unspendableTokensPk); + numvins = tx.vin.size(); numvouts = tx.vout.size(); outputs = inputs = 0; @@ -154,6 +158,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti if((funcid = DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 ) return eval->Invalid("AssetValidate: invalid opreturn payload"); + // find token user cc addr + GetCCaddress(cpTokens, tokensCCaddr, pubkey2pk(origpubkey)); + fprintf(stderr,"AssetValidate (%c)\n",funcid); if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 ) @@ -162,8 +169,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("cant find asset2 create txid"); else if( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("illegal asset vin0"); - else if( numvouts < 1 ) - return eval->Invalid("no vouts"); + else if( numvouts < 2 ) + return eval->Invalid("too few vouts"); // it was if(numvouts < 1) but it refers at least to vout[1] below else if( funcid != 'c' ) { /* if( funcid == 't' ) @@ -223,7 +230,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] //vout.1: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['o'] - if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) + if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( ConstrainVout(tx.vout[0],0, origaddr, nValue) == 0 ) return eval->Invalid("invalid refund for cancelbuy"); @@ -243,7 +250,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.4: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey] preventCCvouts = 4; - if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) + + if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillbuy"); @@ -255,12 +263,12 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("locked value doesnt match vout0+1 fillbuy"); else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if( ConstrainVout(tx.vout[2], 1, CCaddr, 0) == 0 ) + if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, 0) == 0 ) // tokens on user cc addr return eval->Invalid("vout2 doesnt go to origpubkey fillbuy"); else if ( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy"); } - else if( ConstrainVout(tx.vout[2], 1, CCaddr, inputs) == 0 ) + else if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, inputs) == 0 ) // tokens on user cc addr return eval->Invalid("vout2 doesnt match inputs fillbuy"); else if( ConstrainVout(tx.vout[1],0,0,0) == 0 ) return eval->Invalid("vout1 is CC for fillbuy"); @@ -268,7 +276,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("mismatched remainder for fillbuy"); else if( remaining_price != 0 ) { - if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) + if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins on asset unspendable cc addr return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy"); } } @@ -287,16 +295,16 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti preventCCvouts = 1; if( remaining_price == 0 ) return eval->Invalid("illegal null remaining_price for selloffer"); - if( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) + if( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) // is cc change present? { preventCCvouts++; - if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) - return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); + if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also vout[0] + return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer"); else if( tx.vout[0].nValue + tx.vout[1].nValue != inputs ) return eval->Invalid("mismatched vout0+vout1 total for selloffer"); } - else if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, inputs) == 0 ) - return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); + else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // no cc change, just vout[0] + return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer"); //fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price); break; @@ -306,9 +314,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] //vout.1: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] - if( (assetoshis= AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) + if( (assetoshis= AssetValidateSellvin(cpTokens, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); - else if( ConstrainVout(tx.vout[0], 1, CCaddr, assetoshis) == 0 ) + else if( ConstrainVout(tx.vout[0], 1, tokensCCaddr, assetoshis) == 0 ) return eval->Invalid("invalid vout for cancel"); preventCCvins = 2; preventCCvouts = 1; @@ -323,7 +331,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //'S'.vout.2: vin.2 value to original pubkey [origpubkey] //vout.3: normal output for change (if any) //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - if( (assetoshis = AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) + if( (assetoshis = AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillask"); @@ -341,8 +349,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("normal vout1 for fillask"); else if( remaining_price != 0 ) { - if ( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr,0) == 0 ) - return eval->Invalid("mismatched vout0 AssetsCCaddr for fill"); + if ( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr,0) == 0 ) + return eval->Invalid("mismatched vout0 TokenCCaddr for fill"); } } fprintf(stderr,"fill validated\n"); @@ -363,7 +371,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false ) // eval->Invalid("asset2 inputs != outputs"); - if( (assetoshis= AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, CCaddr, origaddr, tx, assetid)) == 0 ) + if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillex"); @@ -375,7 +383,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("locked value doesnt match vout0+1 fillex"); else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if( ConstrainVout(tx.vout[2], 1, CCaddr, 0) == 0 ) + if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, 0) == 0 ) return eval->Invalid("vout2 doesnt go to origpubkey fillex"); else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) { @@ -383,7 +391,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("asset inputs doesnt match vout2+3 fillex"); } } - else if( ConstrainVout(tx.vout[2], 1, CCaddr, inputs) == 0 ) + else if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, inputs) == 0 ) return eval->Invalid("vout2 doesnt match inputs fillex"); else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 ) return eval->Invalid("vout1 is CC for fillex"); @@ -394,7 +402,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("normal vout1 for fillex"); else if( remaining_price != 0 ) { - if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) + if( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) // TODO: unsure about this, but this is not impl yet anyway return eval->Invalid("mismatched vout0 AssetsCCaddr for fillex"); } } diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index 5d919d6e8..9ba6d4a84 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -326,7 +326,9 @@ std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingt CCchange = (inputs - amount); mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,mypk)); // add addr2 - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',bettoken,zeroid,0,Mypubkey()))); + + std::vector voutTokenPubkeysEmpty; //TODO: add token vout pubkeys + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',bettoken,zeroid,0, voutTokenPubkeysEmpty, Mypubkey()))); } else { diff --git a/src/script/script.cpp b/src/script/script.cpp index 475acdfd5..ba3c7f78f 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -407,6 +407,20 @@ bool CScript::MayAcceptCryptoCondition() const cc_free(cond); return out; } +struct CC *CScript::GetCryptoCondition() const +{ + // Get the type mask of the condition + const_iterator pc = this->begin(); + vector data; + opcodetype opcode; + if (!this->GetOp(pc, opcode, data)) return NULL; + if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return NULL; + struct CC *cond = cc_readConditionBinary(data.data(), data.size()); + if (!cond) return NULL; + //bool out = IsSupportedCryptoCondition(cond); + //cc_free(cond); + return cond; +} bool CScript::IsCoinImport() const { diff --git a/src/script/script.h b/src/script/script.h index b1294ab25..68757ef12 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -601,6 +601,8 @@ public: bool IsPayToCryptoCondition() const; bool IsCoinImport() const; bool MayAcceptCryptoCondition() const; + struct CC *GetCryptoCondition() const; + /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; From da58ead2d35ed374fa24b867d65b75a4e1ecc84c Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 4 Jan 2019 16:06:37 +0100 Subject: [PATCH 004/106] Prevent sell and buy offers to be canceled by anybody (#9) - Prevent sell and buy offers to be canceled by anybody --- src/cc/CCassetsCore.cpp | 2 ++ src/cc/CCassetstx.cpp | 28 ++++++++++++------ src/cc/CCtx.cpp | 3 +- src/cc/assets.cpp | 63 ++++++++++++++++++----------------------- 4 files changed, 52 insertions(+), 44 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 837c4361e..f0afd2b84 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -432,6 +432,8 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr return(0); else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("invalid normal vout0 for buyvin"); + else if ( vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("invalid normal vout1 for buyvin"); else { //fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr); diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index fe86d58de..a1ec8a816 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -371,7 +371,7 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in mypk = pubkey2pk(Mypubkey()); - if ((inputs = AddNormalinputs(mtx, mypk, bidamount+txfee, 64)) > 0) + if ((inputs = AddNormalinputs(mtx, mypk, bidamount+(2*txfee), 64)) > 0) { std::cerr << "CreateBuyOffer() inputs=" << inputs << std::endl; if (inputs < bidamount+txfee) { @@ -382,7 +382,7 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in CPubKey unspendablePubkey = GetUnspendable(cpAssets, 0); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendablePubkey)); - + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); std::vector voutTokenPubkeys; // should be empty - no token vouts return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()))); @@ -409,12 +409,12 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p } cpTokens = CCinit(&C, EVAL_TOKENS); // NOTE: tokens is here - + if (txfee == 0) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) + if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60)) > 0) @@ -428,13 +428,14 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p CPubKey unspendablePubkey = GetUnspendable(cpTokens, 0); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, unspendablePubkey)); + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); if (inputs > askamount) CCchange = (inputs - askamount); if (CCchange != 0) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(unspendablePubkey); + voutTokenPubkeys.push_back(unspendablePubkey); opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,opret)); @@ -539,7 +540,9 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) { bidamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets + mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); std::vector voutTokenPubkeys; // should be empty, no tokens vout @@ -554,27 +557,36 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; - struct CCcontract_info *cpTokens, C; + struct CCcontract_info *cpTokens,*cpAssets,C,assetsC; cpTokens = CCinit(&C, EVAL_TOKENS); + cpAssets = CCinit(&assetsC, EVAL_ASSETS); if (txfee == 0) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); if (GetTransaction(asktxid, vintx, hashBlock, false) != 0) { askamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); + mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); - + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(mypk); + char myCCaddr[65]; + uint8_t myPrivkey[32]; + Myprivkey(myPrivkey); + GetCCaddress(cpAssets, myCCaddr, mypk); + CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); + return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey()))); } } diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 3d95d0f17..971ba160d 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -175,7 +175,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran else { fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr); - continue; + return(""); } uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata); if ( cc_signTreeSecp256k1Msg32(cond,privkey,sighash.begin()) != 0 ) @@ -192,6 +192,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran else { fprintf(stderr,"vini.%d has CC signing error address.(%s)\n",i,destaddr); + return(""); } } } else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str()); diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 3a62a526a..127a0e50a 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -45,32 +45,20 @@ valid CC output: create or transfer or buyoffer or selloffer or exchange or cancel or fill - create - vin.0: normal input - vout.0: issuance assetoshis to CC - vout.1: tag sent to normal address of AssetsCCaddress - vout.2: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['c'] [origpubkey] "" "" - - transfer - vin.0: normal input - vin.1 .. vin.n-1: valid CC outputs - vout.0 to n-2: assetoshis output to CC - vout.n-2: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['t'] [assetid] buyoffer: vins.*: normal inputs (bid + change) vout.0: amount of bid to unspendable - vout.1: normal output for change (if any) + vout.1: CC output for marker + vout.2: normal output for change (if any) vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey] cancelbuy: - vin.0: normal input - vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] + vin.0: unspendable.(vout.0 from buyoffer) buyTx.vout[0] + vin.1: CC marker from buyoffer for txfee vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] vout.1: normal output for change (if any) - vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid] + vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid] 0 0 [origpubkey] fillbuy: vin.0: normal input @@ -87,8 +75,9 @@ vin.0: normal input vin.1+: valid CC output for sale vout.0: vin.1 assetoshis output to CC to unspendable - vout.1: CC output for change (if any) - vout.2: normal output for change (if any) + vout.1: CC output for marker + vout.2: CC output for change (if any) + vout.3: normal output for change (if any) vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey] exchange: @@ -100,8 +89,8 @@ vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey] cancel: - vin.0: normal input - vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx + vin.0: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx + vin.1: CC marker from selloffer for txfee vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] vout.1: normal output for change (if any) vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] @@ -213,7 +202,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti case 'b': // buyoffer //vins.*: normal inputs (bid + change) //vout.0: amount of bid to unspendable - //vout.1: normal output for change (if any) + //vout.1: CC output for marker + //vout.2: normal output for change (if any) // vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey] if( remaining_price == 0 ) return eval->Invalid("illegal null amount for buyoffer"); @@ -225,8 +215,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti break; case 'o': // cancelbuy - //vin.0: normal input - //vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] + //vin.0: unspendable.(vout.0 from buyoffer) buyTx.vout[0] + //vin.1: CC marker from buyoffer for txfee //vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] //vout.1: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['o'] @@ -234,7 +224,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return(false); else if( ConstrainVout(tx.vout[0],0, origaddr, nValue) == 0 ) return eval->Invalid("invalid refund for cancelbuy"); - preventCCvins = 2; + preventCCvins = 3; preventCCvouts = 0; fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origaddr); break; @@ -288,29 +278,32 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vin.0: normal input //vin.1+: valid CC output for sale //vout.0: vin.1 assetoshis output to CC to unspendable - //vout.1: CC output for change (if any) - //vout.2: normal output for change (if any) + //vout.1: CC output for marker + //vout.2: CC output for change (if any) + //vout.3: normal output for change (if any) //'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey] //'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey] - preventCCvouts = 1; + preventCCvouts = 2; if( remaining_price == 0 ) return eval->Invalid("illegal null remaining_price for selloffer"); - if( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) // is cc change present? + if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("invalid normal vout1 for sellvin"); + if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) { preventCCvouts++; if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also vout[0] return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer"); - else if( tx.vout[0].nValue + tx.vout[1].nValue != inputs ) - return eval->Invalid("mismatched vout0+vout1 total for selloffer"); + else if( tx.vout[0].nValue + tx.vout[2].nValue != inputs ) + return eval->Invalid("mismatched vout0+vout2 total for selloffer"); } else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // no cc change, just vout[0] return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer"); //fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price); break; - case 'x': // cancel - //vin.0: normal input - //vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx + case 'x': // cancel + //vin.0: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx + //vin.1: CC marker from selloffer for txfee //vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] //vout.1: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] @@ -318,7 +311,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return(false); else if( ConstrainVout(tx.vout[0], 1, tokensCCaddr, assetoshis) == 0 ) return eval->Invalid("invalid vout for cancel"); - preventCCvins = 2; + preventCCvins = 3; preventCCvouts = 1; break; From 5c95c974fdc54d8071329e7372d02203e4d4dc2b Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 4 Jan 2019 16:13:47 +0100 Subject: [PATCH 005/106] Change vin.vout structure in comments --- src/cc/assets.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 127a0e50a..7c413d96a 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -54,10 +54,12 @@ vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey] cancelbuy: - vin.0: unspendable.(vout.0 from buyoffer) buyTx.vout[0] - vin.1: CC marker from buyoffer for txfee + vin.0: normal input + vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] + vin.2: CC marker from buyoffer for txfee vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] - vout.1: normal output for change (if any) + vout.1: vin.2 back to users pubkey + vout.2: normal output for change (if any) vout.n-1: opreturn [EVAL_ASSETS] ['o'] [assetid] 0 0 [origpubkey] fillbuy: @@ -89,10 +91,12 @@ vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey] cancel: - vin.0: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx - vin.1: CC marker from selloffer for txfee + vin.0: normal input + vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx + vin.2: CC marker from selloffer for txfee vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] - vout.1: normal output for change (if any) + vout.1: vin.2 back to users pubkey + vout.2: normal output for change (if any) vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] fillsell: @@ -215,10 +219,12 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti break; case 'o': // cancelbuy - //vin.0: unspendable.(vout.0 from buyoffer) buyTx.vout[0] - //vin.1: CC marker from buyoffer for txfee + //vin.0: normal input + //vin.1: unspendable.(vout.0 from buyoffer) buyTx.vout[0] + //vin.2: CC marker from buyoffer for txfee //vout.0: vin.1 value to original pubkey buyTx.vout[0].nValue -> [origpubkey] - //vout.1: normal output for change (if any) + //vout.1: vin.2 back to users pubkey + //vout.2: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['o'] if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 ) return(false); @@ -302,10 +308,12 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti break; case 'x': // cancel - //vin.0: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx - //vin.1: CC marker from selloffer for txfee + //vin.0: normal input + //vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx + //vin.2: CC marker from selloffer for txfee //vout.0: vin.1 assetoshis to original pubkey CC sellTx/exchangeTx.vout[0].nValue -> [origpubkey] - //vout.1: normal output for change (if any) + //vout.1: vin.2 back to users pubkey + //vout.2: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] if( (assetoshis= AssetValidateSellvin(cpTokens, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); From a0fc5d6ae472cd5830f91a74fa1df6ed48de1108 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 7 Jan 2019 23:30:57 +0500 Subject: [PATCH 006/106] Corrected both Cancels, 'B' and TokenTransfer --- src/Makefile.am | 2 ++ src/cc/CCassetsCore.cpp | 4 +-- src/cc/CCassetstx.cpp | 34 ++++++++++++++++++-------- src/cc/CCtokens.cpp | 54 +++++++++++++++++++++++++++-------------- src/cc/CCtokens.h | 39 ++--------------------------- src/cc/assets.cpp | 2 ++ src/script/script.cpp | 14 ----------- src/script/script.h | 2 -- 8 files changed, 68 insertions(+), 83 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 9588cfe44..5e665cc3c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -384,6 +384,8 @@ libbitcoin_wallet_a_SOURCES = \ transaction_builder.cpp \ wallet/rpcdisclosure.cpp \ wallet/rpcdump.cpp \ + cc/CCtokens.cpp \ + cc/CCassetsCore.cpp \ cc/CCassetstx.cpp \ cc/CCtx.cpp \ wallet/rpcwallet.cpp \ diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index f0afd2b84..67e23837f 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -432,12 +432,12 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr return(0); else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("invalid normal vout0 for buyvin"); - else if ( vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + else if ((funcid = DecodeAssetOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' && vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'? return eval->Invalid("invalid normal vout1 for buyvin"); else { //fprintf(stderr,"have %.8f checking assetid origaddr.(%s)\n",(double)nValue/COIN,origaddr); - if ( vinTx.vout.size() > 0 && (funcid= DecodeAssetOpRet(vinTx.vout[vinTx.vout.size()-1].scriptPubKey, evalCode, assetid,assetid2,tmpprice,tmporigpubkey)) != 'b' && funcid != 'B' ) + if ( vinTx.vout.size() > 0 && funcid != 'b' && funcid != 'B' ) return eval->Invalid("invalid opreturn for buyvin"); else if ( refassetid != assetid ) return eval->Invalid("invalid assetid for buyvin"); diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index a1ec8a816..6bf176f24 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -148,7 +148,7 @@ UniValue AssetOrders(uint256 refassetid) //std::cerr << "addOrders() txid=" << txid.GetHex() << std::endl; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey); + // for logging: funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey); //std::cerr << "addOrders() vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl; if (vintx.vout.size() > 0 && (funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0) { @@ -428,7 +428,7 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p CPubKey unspendablePubkey = GetUnspendable(cpTokens, 0); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, unspendablePubkey)); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker if (inputs > askamount) CCchange = (inputs - askamount); if (CCchange != 0) @@ -526,6 +526,8 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) CPubKey mypk; struct CCcontract_info *cpAssets, C; + uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector dummyOrigpubkey; + cpAssets = CCinit(&C, EVAL_ASSETS); if (txfee == 0) @@ -540,7 +542,11 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) { bidamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets - mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); + + if( DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 'b') + mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b' (not 'B') + // TODO: spend it also in FillBuyOffer? + mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); @@ -559,6 +565,8 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; struct CCcontract_info *cpTokens,*cpAssets,C,assetsC; + uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector dummyOrigpubkey; + cpTokens = CCinit(&C, EVAL_TOKENS); cpAssets = CCinit(&assetsC, EVAL_ASSETS); @@ -574,7 +582,11 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) { askamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); - mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); + + if (DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 's') + mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s' (not 'S') + // TODO: spend it also in FillSell? + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); @@ -663,7 +675,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f // token vout verification pubkeys: std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(unspendableTokensPk); + voutTokenPubkeys.push_back(pubkey2pk(origpubkey)); return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, voutTokenPubkeys, origpubkey))); } else return("dont have any assets to fill bid"); @@ -743,22 +755,24 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt if (assetid2 != zeroid && inputs > paid_nValue) CCchange = (inputs - paid_nValue); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, orig_assetoshis - received_assetoshis, GetUnspendable(cpTokens, NULL))); // 0 tokens cc addr - ask remainder - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //1 tokens to self + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, orig_assetoshis - received_assetoshis, GetUnspendable(cpTokens, NULL))); // vout.0 tokens cc addr - ask remainder + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //vout.1 tokens to self + // NOTE: no marker here + if (assetid2 != zeroid) { std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl; - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //2 tokens... (swap is not implemented yet) + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //vout.2 tokens... (swap is not implemented yet) } else { //std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl; - mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //2 coins normal to whom who asked token + mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins normal to whom who asked token } // not implemented if (CCchange != 0) { std::cerr << "FillSell() WARNING: asset swap not implemented yet! (CCchange)" << std::endl; - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //3 coins in Assets cc addr + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr } // vout verification pubkeys: diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index d9e689f85..8e5d98f47 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -51,14 +51,19 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector origpubkey,st } // this is for other contracts which use tokens and build customized extra payloads to token's opret: -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector payload) +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys) { CScript opret; + uint8_t ccType = 0; + if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) + ccType = voutPubkeys.size(); + //uint8_t evalcode = EVAL_TOKENS; tokenid = revuint256(tokenid); //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; - opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); + //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); + opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; if (ccType >= 1) ss << voutPubkeys[0]; if (ccType == 2) ss << voutPubkeys[1];); return(opret); } @@ -148,6 +153,8 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & char destaddr[64], origaddr[64], CCaddr[64]; std::vector voutTokenPubkeys; + //return true; + numvins = tx.vin.size(); numvouts = tx.vout.size(); outputs = inputs = 0; @@ -161,7 +168,7 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & if (eval->GetTxUnconfirmed(tokenid, createTx, hashBlock) == 0) return eval->Invalid("cant find token create txid"); else if (IsCCInput(tx.vin[0].scriptSig) != 0) - return eval->Invalid("illegal token vin0"); // why? (dimxy) + return eval->Invalid("illegal token vin0"); else if (numvouts < 1) return eval->Invalid("no vouts"); else if (funcid != 'c') @@ -176,10 +183,6 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & } } - // init for forwarding validation call - struct CCcontract_info *cpOther = NULL, C; - if (evalCodeInOpret != EVAL_TOKENS) - cpOther = CCinit(&C, evalCodeInOpret); switch (funcid) { @@ -211,11 +214,17 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & } // forward validation if evalcode in opret is not EVAL_TOKENS - if (cpOther) - return cpOther->validate(cpOther, eval, tx, nIn); - else - return eval->Invalid("unsupported evalcode in opret"); + // init for forwarding validation call + if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS? + struct CCcontract_info *cpOther = NULL, C; + cpOther = CCinit(&C, evalCodeInOpret); + if (cpOther) + return cpOther->validate(cpOther, eval, tx, nIn); + else + return eval->Invalid("unsupported evalcode in opret"); + } + return true; // what does this do? // return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); } @@ -404,7 +413,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*/, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeysEmpty); + tokenoshis = IsTokensvout(goDeeper, false/*<--do not have pubkeys for now*/, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeysEmpty); tokenValIndentSize--; if (tokenoshis != 0) { @@ -435,7 +444,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t if (inputs != outputs) { if (tx.GetHash() != tokenid) - std::cerr << indentStr << "TokenExactAmounts() found unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << " and this is not create tx" << std::endl; + std::cerr << indentStr << "TokenExactAmounts() found unequal token cc inputs=" << inputs << " vs cc outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << " and this is not the create tx" << std::endl; return false; // do not call eval->Invalid() here! } else @@ -477,7 +486,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C 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, cp, NULL, vopretExtra, vintx, vout, tokenid, vinPubkeysEmpty)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) + 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) { if (total != 0 && maxinputs != 0) mtx.vin.push_back(CTxIn(txid, vout, CScript())); @@ -559,13 +568,22 @@ std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector d if (inputs > total) CCchange = (inputs - total); //for (i=0; i voutTokenPubkeys; + voutTokenPubkeys.push_back(pubkey2pk(destpubkey)); // dest pubkey for validating vout + + return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet('t', EVAL_TOKENS, assetid, voutTokenPubkeys))); // By setting EVAL_TOKENS we're getting out from assets validation code + } + else { + fprintf(stderr, "not enough CC token inputs for %.8f\n", (double)total / COIN); } - else fprintf(stderr, "not enough CC asset inputs for %.8f\n", (double)total / COIN); //} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size()); } + else { + fprintf(stderr, "not enough normal inputs for txfee\n"); + } return(""); } \ No newline at end of file diff --git a/src/cc/CCtokens.h b/src/cc/CCtokens.h index 8ecbc1094..f65a56b41 100644 --- a/src/cc/CCtokens.h +++ b/src/cc/CCtokens.h @@ -31,46 +31,11 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t //int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description); std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys); -//this is in CCinclude.h int64_t AddTokenInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); +//this is in CCinclude.h int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); //this is in CCinclude.h uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); -/* -// CCassetsCore -CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,std::string name,std::string description); -CScript EncodeAssetOpRet(uint8_t funcid,uint256 assetid,uint256 assetid2,int64_t price,std::vector origpubkey); -bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); -//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); -bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CTransaction &tx); -int64_t IsAssetvout(bool compareTotals, struct CCcontract_info *cp, Eval* eval, int64_t &price, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid); -bool ValidateBidRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); -bool ValidateAskRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); -bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice); -bool SetBidFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); -bool SetAskFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); -bool SetSwapFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); -int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid); -int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid); -bool AssetExactAmounts(bool compareTotals, struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid); - -// CCassetstx -int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); -int64_t AddAssetInputs(CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); -UniValue AssetOrders(uint256 tokenid); -UniValue AssetInfo(uint256 tokenid); -UniValue AssetList(); -std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description); -std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total); -std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode); - -std::string CreateBuyOffer(int64_t txfee,int64_t bidamount,uint256 assetid,int64_t pricetotal); -std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid); -std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t fillamount); -std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t pricetotal); -std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 assetid2,int64_t pricetotal); -std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid); -std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillamount); -*/ #endif diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 7c413d96a..ea44453ff 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -135,6 +135,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti uint8_t funcid, evalCodeInOpret; char destaddr[64], origaddr[64], assetsCCaddr[64], tokensCCaddr[64]; + //return true; + // we need this for validating tokens' vins/vous: struct CCcontract_info *cpTokens, tokensC; cpTokens = CCinit(&tokensC, EVAL_TOKENS); diff --git a/src/script/script.cpp b/src/script/script.cpp index ba3c7f78f..475acdfd5 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -407,20 +407,6 @@ bool CScript::MayAcceptCryptoCondition() const cc_free(cond); return out; } -struct CC *CScript::GetCryptoCondition() const -{ - // Get the type mask of the condition - const_iterator pc = this->begin(); - vector data; - opcodetype opcode; - if (!this->GetOp(pc, opcode, data)) return NULL; - if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return NULL; - struct CC *cond = cc_readConditionBinary(data.data(), data.size()); - if (!cond) return NULL; - //bool out = IsSupportedCryptoCondition(cond); - //cc_free(cond); - return cond; -} bool CScript::IsCoinImport() const { diff --git a/src/script/script.h b/src/script/script.h index 68757ef12..b1294ab25 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -601,8 +601,6 @@ public: bool IsPayToCryptoCondition() const; bool IsCoinImport() const; bool MayAcceptCryptoCondition() const; - struct CC *GetCryptoCondition() const; - /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; From 90f682f022ba5284ae506e31d0522284e85045c2 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 7 Jan 2019 19:00:34 +0500 Subject: [PATCH 007/106] Heir corrected for Tokens contract --- src/cc/CCassetstx.cpp | 2 +- src/cc/heir.cpp | 89 ++++++++++++++++++++++++++++++++---------- src/cc/heir_validate.h | 43 ++++++++------------ 3 files changed, 85 insertions(+), 49 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 6bf176f24..1c2012534 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -597,7 +597,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) uint8_t myPrivkey[32]; Myprivkey(myPrivkey); GetCCaddress(cpAssets, myCCaddr, mypk); - CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); + CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey()))); } diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 90557d7ac..7512b54ed 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -14,7 +14,7 @@ ******************************************************************************/ #include "CCHeir.h" -#include "CCassets.h" +#include "CCtokens.h" #include "heir_validate.h" @@ -433,47 +433,79 @@ bool HeirExactAmounts(struct CCcontract_info* cp, Eval* eval, const CTransaction } // makes coin initial tx opret -CScript EncodeHeirCreateOpRet(uint8_t eval, uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) +CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName); + uint8_t evalcode = EVAL_HEIR; + + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName); } // makes coin additional tx opret -CScript EncodeHeirOpRet(uint8_t eval, uint8_t funcid, uint256 fundingtxid) +CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid) { + uint8_t evalcode = EVAL_HEIR; + fundingtxid = revuint256(fundingtxid); - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)funcid << fundingtxid); + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)funcid << fundingtxid); } // makes opret for tokens while they are inside Heir contract address space - initial funding -CScript EncodeHeirAssetsCreateOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) +CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) { + uint8_t evalcode = EVAL_TOKENS; + uint8_t ccType = 0; + if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) + ccType = voutPubkeys.size(); + tokenid = revuint256(tokenid); - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)'t' << tokenid << (uint8_t)funcid << ownerPubkey << heirPubkey << inactivityTimeSec << hearName); + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)'t' << tokenid << (uint8_t)funcid << ccType; if (ccType >= 1) ss << voutPubkeys[0]; if (ccType == 2) ss << voutPubkeys[1]; ss << ownerPubkey << heirPubkey << inactivityTimeSec << hearName); } // makes opret for tokens while they are inside Heir contract address space - additional funding -CScript EncodeHeirAssetsOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, uint256 fundingtxid) +CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid) { + uint8_t evalcode = EVAL_HEIR; + uint8_t ccType = 0; + if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) + ccType = voutPubkeys.size(); + tokenid = revuint256(tokenid); fundingtxid = revuint256(fundingtxid); - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)eval << (uint8_t)'t' << tokenid << (uint8_t)funcid << fundingtxid); + return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)'t' << tokenid << ccType; if (ccType >= 1) ss << voutPubkeys[0]; if (ccType == 2) ss << voutPubkeys[1]; ss << (uint8_t)funcid << fundingtxid); } +// helper for decode heir opret payload +// NOTE: Heir for coins has the same opret as Heir for tokens +uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret) { + uint8_t heirFuncId = 0; + + bool result = E_UNMARSHAL(vopretExtra, { ss >> heirFuncId; ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; if (IS_CHARINSTR(heirFuncId, "F")) { ss >> heirName; } if (IS_CHARINSTR(heirFuncId, "AC")) { ss >> fundingTxidInOpret; } }); + if (!result /*|| assetFuncId != 't' -- any tx is ok*/) + return (uint8_t)0; + + return heirFuncId; +} /** * decode opret vout for Heir contract */ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, bool noLogging) { - std::vector vopret; - uint8_t opretEval = 0; - uint8_t funcId = 0; + uint8_t evalCodeInOpret = 0; + + std::vector vopretExtra; + uint256 dummyTokenid; + std::vector voutPubkeysDummy; fundingTxidInOpret = zeroid; //to init + tokenid = zeroid; - GetOpReturnData(scriptPubKey, vopret); - if (vopret.size() > 1) { + // First - decode token opret: + uint8_t funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra); + + //GetOpReturnData(scriptPubKey, vopret); + + if (funcId != 0 && vopretExtra.size() > 1) { // TODO: add this funcId cond in Assets too // NOTE: it unmarshals for all F, A and C - Helper::UnmarshalOpret(vopret, opretEval, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret); + uint8_t heirFuncId = _UnmarshalOpret(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret); /* std::cerr << "DecodeHeirOpRet() e=" << (int)e @@ -484,14 +516,14 @@ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 & */ //if (e == EVAL_HEIR && IS_CHARINSTR(funcId, "FAC")) - if (opretEval == EVAL_HEIR && Helper::isMyFuncId(funcId)) { + if (evalCodeInOpret == EVAL_HEIR && Helper::isMyFuncId(heirFuncId)) { tokenid = revuint256(tokenid); fundingTxidInOpret = revuint256(fundingTxidInOpret); - return funcId; + return heirFuncId; } else { - if(!noLogging) std::cerr << "DecodeHeirOpRet() warning unexpected OP_RETURN eval=" << (int)opretEval << " or field type=" << (char)(funcId ? funcId : ' ') << '\n'; + if(!noLogging) std::cerr << "DecodeHeirOpRet() warning unexpected OP_RETURN eval=" << (int)evalCodeInOpret << " or field type=" << (char)(heirFuncId ? heirFuncId : ' ') << '\n'; } } else { @@ -843,10 +875,15 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); } + // add 1of2 vout validation pubkeys: + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(myPubkey); + voutTokenPubkeys.push_back(heirPubkey); + // add change for txfee and opreturn vouts and sign tx: return (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, // CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'F' << myPubkey << heirPubkey << inactivityTimeSec << heirName))); - Helper::makeCreateOpRet(tokenid, myPubkey, heirPubkey, inactivityTimeSec, heirName))); + Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName))); } else // TODO: need result return unification with heiradd and claim std::cerr << "HeirFund() could not find owner inputs" << std::endl; @@ -928,9 +965,14 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); } + // add 1of2 vout validation pubkeys: + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(ownerPubkey); + voutTokenPubkeys.push_back(heirPubkey); + // add opreturn 'A' and sign tx: // this txfee ignored std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeAddOpRet(tokenid, fundingtxid))); + Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid))); result.push_back(Pair("result", "success")); result.push_back(Pair("hextx", rawhextx)); @@ -1068,9 +1110,14 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + // add 1of2 vout validation pubkeys: + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(ownerPubkey); + voutTokenPubkeys.push_back(heirPubkey); + // add opreturn 'C' and sign tx: // this txfee will be ignored std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeClaimOpRet(tokenid, fundingtxid)); + Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid)); result.push_back(Pair("result", "success")); result.push_back(Pair("hextx", rawhextx)); diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 8b432e8e0..108562e24 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -11,12 +11,12 @@ // makes coin initial tx opret -CScript EncodeHeirCreateOpRet(uint8_t eval, uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); +CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); // makes coin additional tx opret -CScript EncodeHeirOpRet(uint8_t eval, uint8_t funcid, uint256 fundingtxid); +CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid); -CScript EncodeHeirAssetsCreateOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName); -CScript EncodeHeirAssetsOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, uint256 fundingtxid); +CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName); +CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid); //CScript EncodeHeirConvertedAssetsOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 fundingtxid); template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, bool &isHeirSpendingBegan); @@ -37,18 +37,14 @@ public: return AddNormalinputs(mtx, ownerPubkey, total, maxinputs); } - static CScript makeCreateOpRet(uint256 dummyid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { - return EncodeHeirCreateOpRet((uint8_t)EVAL_HEIR, (uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + static CScript makeCreateOpRet(uint256 dummyid, std::vector dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { + return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName); } - static CScript makeAddOpRet(uint256 dummyid, uint256 fundingtxid) { - return EncodeHeirOpRet((uint8_t)EVAL_HEIR, (uint8_t)'A', fundingtxid); + static CScript makeAddOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid) { + return EncodeHeirOpRet((uint8_t)'A', fundingtxid); } - static CScript makeClaimOpRet(uint256 dummyid, uint256 fundingtxid) { - return EncodeHeirOpRet((uint8_t)EVAL_HEIR, (uint8_t)'C', fundingtxid); - } - - static void UnmarshalOpret(std::vector vopret, uint8_t &e, uint8_t &funcId, uint256 &dummytokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret) { - E_UNMARSHAL(vopret, { ss >> e; ss >> funcId; ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; if (IS_CHARINSTR(funcId, "F")) { ss >> heirName; } if (IS_CHARINSTR(funcId, "AC")) { ss >> fundingTxidInOpret; } }); + static CScript makeClaimOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid) { + return EncodeHeirOpRet((uint8_t)'C', fundingtxid); } static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } @@ -64,29 +60,22 @@ public: // helper class to allow polymorphic behaviour for HeirXXX() functions in case of tokens class TokenHelper { public: - static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); } static uint8_t getMyEval() { return EVAL_TOKENS; } static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { return AddTokenCCInputs(cp, mtx, ownerPubkey, tokenid, total, maxinputs); } - static CScript makeCreateOpRet(uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { - return EncodeHeirAssetsCreateOpRet((uint8_t)EVAL_HEIR, (uint8_t)'F', tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { + return EncodeHeirTokensCreateOpRet((uint8_t)'F', tokenid, voutTokenPubkeys, ownerPubkey, heirPubkey, inactivityTimeSec, heirName); } - static CScript makeAddOpRet(uint256 tokenid, uint256 fundingtxid) { - return EncodeHeirAssetsOpRet((uint8_t)EVAL_HEIR, (uint8_t)'A', tokenid, fundingtxid); + static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid) { + return EncodeHeirTokensOpRet((uint8_t)'A', tokenid, voutTokenPubkeys, fundingtxid); } - static CScript makeClaimOpRet(uint256 tokenid, uint256 fundingtxid) { - return EncodeHeirAssetsOpRet((uint8_t)EVAL_HEIR, (uint8_t)'C', tokenid, fundingtxid); + static CScript makeClaimOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid) { + return EncodeHeirTokensOpRet((uint8_t)'C', tokenid, voutTokenPubkeys, fundingtxid); } - static void UnmarshalOpret(std::vector vopret, uint8_t &e, uint8_t &funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingtxidInOpret) { - uint8_t assetFuncId = '\0'; - bool result = E_UNMARSHAL(vopret, { ss >> e; ss >> assetFuncId; ss >> tokenid; ss >> funcId; if (IS_CHARINSTR(funcId, "F")) { ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; } if (IS_CHARINSTR(funcId, "AC")) { ss >> fundingtxidInOpret; } }); - if (!result /*|| assetFuncId != 't' -- any tx is ok*/) - funcId = 0; - } static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) { From d1bd5b3b6c0cc645addf8889e7252baa9ca6b413 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 9 Jan 2019 16:58:52 +0500 Subject: [PATCH 008/106] Squashed commit of the following: commit 843168eddff34390f19fa661ac6315e1a51aafe2 Author: dimxy Date: Wed Jan 9 14:34:03 2019 +0500 logging improved for CCtokens.cpp commit 43c5b3a5c4e36e76a235f987e07fe893d941d95e Author: dimxy Date: Wed Jan 9 14:23:41 2019 +0500 more extra logging disabled for heir and token commit a3f7ca963a0042237f4c97d6d89852646b541c6c Author: dimxy Date: Wed Jan 9 14:13:58 2019 +0500 more extra logging disabled commit f4dec8f8ad733c5a61dd0fc9f3decd103dd7a0c3 Author: dimxy Date: Wed Jan 9 14:05:45 2019 +0500 more extra logging disabled commit eb9a41472004ccdacdacfc12b79880ac6da390ee Author: dimxy Date: Wed Jan 9 13:50:11 2019 +0500 extra logging disabled in heir and tokens commit 0fe01c8a7b52b03e0c0a3ba5d77f916862031d23 Author: dimxy Date: Wed Jan 9 13:15:08 2019 +0500 heir normal input validator changed to CNullValidator commit 3b86e87c83b6993d5a3b4c056c10120223e8c9ed Author: dimxy Date: Wed Jan 9 12:58:03 2019 +0500 enabled logiing in FinalizeCCtx commit 2ea87c1b3c7967b316d22e2e65fc3c0203cc4b03 Author: dimxy Date: Wed Jan 9 12:37:43 2019 +0500 corrected parameters for tests commit 216eb4ed84c6fd23e3fc22cd79509a09c8504c0c Author: dimxy Date: Wed Jan 9 12:22:30 2019 +0500 changed to eval_assets for test commit 2af850f06a4692200864a316208cdfc0709b1634 Author: dimxy Date: Wed Jan 9 02:42:43 2019 +0500 heiradd loggin vin commit 28e033d2b2a1a01b2bc9c2d51a81b61ae53f3a29 Author: dimxy Date: Wed Jan 9 02:04:33 2019 +0500 logging added commit ef1dbc504c5984a4997b5e06e736fa7b5b4e125d Author: dimxy Date: Wed Jan 9 01:29:46 2019 +0500 logging added and corrected commit 98c1e5a6896a97667c9d64f347c26b36c6a320a9 Author: dimxy Date: Wed Jan 9 01:05:17 2019 +0500 corrected isHeirSpendingBegan init in _UnmarshalOpret commit 6006f073bfc136ed06c1636b3e6ffa7b403ce1d9 Author: dimxy Date: Wed Jan 9 01:01:18 2019 +0500 corrected dummyIsHeirSpendingBegan using commit 9a95edf4e311a80538dd7b13aeeb201e97474ee8 Author: dimxy Date: Wed Jan 9 00:53:50 2019 +0500 isHeirSpendingBegan is put in opret commit 4bd210709626e2f8b99889e50410eb0f75b3dbda Author: dimxy Date: Tue Jan 8 20:16:20 2019 +0500 added logging to _FindLastextFundingTx for print C vouts commit 3603b49c1143b1efe82dd545b9d7dca43f5bcec0 Author: dimxy Date: Tue Jan 8 19:25:11 2019 +0500 corrected isHeirSpendingBegun calc commit e7d6923d4be080a5e98405634fafb175fa55f801 Author: dimxy Date: Tue Jan 8 18:43:35 2019 +0500 yet another cpToken correction in RunValidators commit e425dcc4497652a062b45d4a5ce4c137bd2caa3d Author: dimxy Date: Tue Jan 8 18:22:08 2019 +0500 changed cp param to cpTokens for heir tokens in validation commit a4420f30d42d93dbc2729db4a5b2895d4b16d22b Author: dimxy Date: Tue Jan 8 17:11:10 2019 +0500 corrected EVAL_HEIR in create opret commit 788d75263fd5aaa7b66417441622c9bb6603ab81 Author: dimxy Date: Tue Jan 8 16:41:07 2019 +0500 corrected opret forming for 'F', tokens commit 92bf6c53b36a5a4450b5c7079383792d634d61a7 Author: dimxy Date: Tue Jan 8 16:12:09 2019 +0500 _UnmarshalOpret corrected for non F commit e4eb26e875d44f3e4c1d45aff6df8a7026b3329a Author: dimxy Date: Tue Jan 8 15:26:34 2019 +0500 Revert "CCduration debug logging added" This reverts commit 5ffc2b0a8b49d387cd175754738d2c07701c7856. commit ce97ac88af0b87b304ad1fc9cb29db0803d0bd42 Author: dimxy Date: Tue Jan 8 15:17:10 2019 +0500 changed pindex to pindexTip in CCduration for better reading commit 5ffc2b0a8b49d387cd175754738d2c07701c7856 Author: dimxy Date: Tue Jan 8 14:43:07 2019 +0500 CCduration debug logging added commit 34afdd16f0f6b5b97da864f082dcd019a7566da7 Author: dimxy Date: Tue Jan 8 12:23:31 2019 +0500 corrected again order to DecodeOpRet call in heir commit bba6149969ea23aa4e3c6263a36bae0ba7fa6f5d Author: dimxy Date: Tue Jan 8 12:17:11 2019 +0500 logging added in IsHeirFundingVout commit 6c5d4b313ef3e54cb5eb2bf67b2fa78d9ffd0b04 Author: dimxy Date: Tue Jan 8 12:02:15 2019 +0500 logging added to Add1of2AddrInputs commit 40d6d84971a8ed764523567f08df4c74fda4f12d Author: dimxy Date: Tue Jan 8 11:36:23 2019 +0500 corrected vopretExtra getting for heir for coins commit 36061d25fb8992551915afc3dd0600878a64c540 Author: dimxy Date: Tue Jan 8 11:13:30 2019 +0500 corrected CCinit C-param separate commit 0a6710433868c315afe3f656c1bc5f5138fe5288 Author: dimxy Date: Tue Jan 8 10:58:19 2019 +0500 logging added in decodeheiropret commit 2503d8cb59b94b024a9ded43a0602f89800a9549 Author: dimxy Date: Tue Jan 8 10:39:21 2019 +0500 corrected decode opret for heir for coins --- src/cc/CCtokens.cpp | 19 +- src/cc/CCtx.cpp | 1 - src/cc/heir.cpp | 534 ++++++++++++++--------------------------- src/cc/heir_validate.h | 84 +++---- 4 files changed, 237 insertions(+), 401 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 8e5d98f47..4a2c6031e 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -92,7 +92,7 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 script = (uint8_t *)vopret.data(); tokenid = zeroid; - if (script != 0 /*enable all evals: && script[0] == EVAL_TOKENS*/) + if (script != 0 && vopret.size() > 2) { // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! bool isEof = true; @@ -114,7 +114,7 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 { if (!(ccType >= 0 && ccType <= 2)) { //incorrect ccType - std::cerr << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << std::endl; + std::cerr << "DecodeTokenOpRet() incorrect ccType=" << (int)ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl; return (uint8_t)0; } @@ -128,7 +128,7 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 tokenid = revuint256(tokenid); return(funcId); } - std::cerr << "DecodeTokenOpRet() warning: bad opret format, isEof=" << isEof << " ccType=" << ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl; + std::cerr << "DecodeTokenOpRet() bad opret format, isEof=" << isEof << " ccType=" << ccType << " tokenid=" << revuint256(tokenid).GetHex() << std::endl; return (uint8_t)0; default: @@ -136,6 +136,9 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 return (uint8_t)0; } } + else { + std::cerr << "DecodeTokenOpRet() empty opret, could not parse" << std::endl; + } return (uint8_t)0; } @@ -247,7 +250,7 @@ bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, tokenidOpret, voutPubkeys, vopretExtra)) == 0) { - std::cerr << indentStr << "ValidateTokenOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl; + std::cerr << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl; return(false); } else if (funcid == 'c') @@ -330,7 +333,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c testVout = MakeCC1of2vout(EVAL_TOKENS, 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; + //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; return tx.vout[v].nValue; } } @@ -340,7 +343,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c CTxOut testVout = MakeCC1vout(EVAL_TOKENS, 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; + //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; return tx.vout[v].nValue; } } @@ -382,7 +385,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t if (cc_typeId(cond) == CC_Secp256k1) { *(CPubKey*)_.context = buf2pk(cond->publicKey); - std::cerr << "findEval found pubkey=" << HexStr(*(CPubKey*)_.context) << std::endl; + //std::cerr << "findEval found pubkey=" << HexStr(*(CPubKey*)_.context) << std::endl; r = true; } // false for a match, true for continue @@ -483,7 +486,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C 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) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 971ba160d..79473b87a 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -135,7 +135,6 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = myprivkey; cond = mycond; - } else if ( strcmp(destaddr,unspendable) == 0 ) { diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 7512b54ed..d75580cec 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -23,145 +23,20 @@ class TokenHelper; /* The idea of Heir CC is to allow crypto inheritance. - A special 1of2 CC address is created that is freely spendable by the creator. The heir is only allowed to spend after the specified amount of idle blocks. The idea is that if the address doesnt spend any funds for a year (or whatever amount set), then it is time to allow the heir to spend. The design requires the heir to spend all the funds at once + A special 1of2 CC address is created that is freely spendable by the creator (funds owner). + The owner may add additional funds to this 1of2 address. + The heir is only allowed to spend after "the specified amount of idle blocks" (changed to "the owner inactivityTime"). + The idea is that if the address doesnt spend any funds for a year (or whatever amount set), then it is time to allow the heir to spend. + "The design requires the heir to spend all the funds at once" (this requirement was changed to "after the inactivity time both the heir and owner may freely spend available funds") + After the first heir spending a flag is set that spending is allowed for the heir whether the owner adds more funds or spends them. + This Heir contract supports both coins and tokens. */ // tx validation code -// this is for indentation of debug log messages (in recursive calls): -//extern thread_local uint32_t assetValIndentSize; - -// check if vout is cc addr and also check sum(inputs) == sum(outputs) for the passed tx, if requested -int64_t IsHeirvout(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 tokenid, const CTransaction& tx, int32_t v) -{ - //std::string indentStr = std::string().append(assetValIndentSize, '.'); - - //std::cerr << indentStr << "IsHeirvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << std::boolalpha << " compareTotals=" << compareTotals << std::endl; - if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition()) - { - //std::cerr << indentStr << "IsHeirvout() IsPayToCryptoCondition=true for txid=" << tx.GetHash().GetHex() << std::endl; - /*if (compareTotals) { // totally there are only 2 levels actually - - // call recursively HeirExactTokenAmounts and compare ccinputs = ccoutputs for this tx: - assetValIndentSize++; - const bool isEqual = HeirExactTokenAmounts(false, cpHeir, eval, tokenid, tx); - assetValIndentSize--; - - if (!isEqual) { // ccInputs != ccOutputs means a problem - //std::cerr << indentStr << "IsHeirvout() warning: detected suspicious tx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs, checking further if it is the tokenbase tx" << std::endl; - // if ccInputs != ccOutputs and it is not the 'tokenbase' tx means it is possibly fake tx (dimxy): - if (tokenid != zeroid && tokenid != tx.GetHash()) { - std::cerr << indentStr << "IsHeirvout() warning: detected bad tx=" << tx.GetHash().GetHex() << ": cc inputs != cc outputs and not the 'tokenbase' tx, skipping this tx" << std::endl; - return 0; - } - } - }*/ - - // TODO: add some validation here - - // lets check asset opreturn for this heir or assets tx (dimxy): - /* - int64_t dummyPrice; std::vector dummyOrigpubkey; - - const bool valOpret = ValidateAssetOpret(tx, v, tokenid, dummyPrice, dummyOrigpubkey); - //std::cerr << indentStr << "IsHeirvout() ValidateAssetOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << std::endl; - if (valOpret) { - std::cerr << indentStr << "IsHeirvout() opret is true, return value=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << std::endl; - return(tx.vout[v].nValue); - }*/ - - return(tx.vout[v].nValue); - } - //std::cerr << indentStr << "IsHeirvout() return value=0" << std::endl; - return(0); -} - -// this function validates that tx cc outputs == cc inputs, -// that is there is no fake token supply from normal inputs (except the initial tokenbase tx) -// the cc inputs are allowed only from the Assets or Heir contracts -/*bool HeirExactTokenAmounts(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 tokenid, const CTransaction &tx) -{ - static uint256 zerohash; - CTransaction vinTx; - uint256 hashBlock, activehash; - int64_t inputs = 0, outputs = 0, assetoshis; - - struct CCcontract_info *cpAssets, cAssets; - cpAssets = CCinit(&cAssets, EVAL_ASSETS); // init also tokens CC contract to check its cc addresses too - - std::string indentStr = std::string().append(assetValIndentSize, '.'); - - int32_t numvins = tx.vin.size(); - int32_t numvouts = tx.vout.size(); - for (int32_t i = 0; i < numvins; i++) - { - //std::cerr << indentStr << "HeirExactTokenAmounts() vin i=" << i << " cpHeir->ismyvin()=" << std::boolalpha << (*cpHeir->ismyvin)(tx.vin[i].scriptSig) << " cpAssets->ismyvin()=" << (*cpAssets->ismyvin)(tx.vin[i].scriptSig) << std::endl; - - // checking that vin is either from heir or assets: - if ((*cpHeir->ismyvin)(tx.vin[i].scriptSig) || (*cpAssets->ismyvin)(tx.vin[i].scriptSig)) - { - //std::cerr << indentStr; fprintf(stderr,"vini.%d check mempool\n",i); - if ((eval && !eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock)) || !myGetTransaction(tx.vin[i].prevout.hash, vinTx, hashBlock)) { - std::cerr << indentStr << "HeirExactTokenAmounts(): can't get vintx transaction txid=" << tx.vin[i].prevout.hash.GetHex() << std::endl; - return (eval) ? eval->Invalid("cant find vinTx") : false; - } - else - { - //std::cerr << indentStr; fprintf(stderr,"vini.%d check hash and vout\n",i); - if (hashBlock == zerohash) { - std::cerr << indentStr << "HeirExactTokenAmounts(): can't get vintx from mempool, txid=" << tx.vin[i].prevout.hash.GetHex() << std::endl; - return (eval) ? eval->Invalid("cant Heir from mempool") : false; - } - - std::string dummyRefcoin; uint256 dummyBindtxid, dummyDeposittxid; CPubKey dummyDestpub; int64_t dummyAmount; - uint256 dummyAssetid2; - std::vector dummyOrigpubkey; - - // Note: if tokenid is zeroid, it may mean we are on the first level and just called from HeirValidate, validating claim 't' tx, - // then let's find the tokenid ourselves: - if (tokenid == zeroid && DecodeAssetOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, dummyAssetid2, dummyAmount, dummyOrigpubkey) == 't') { - //std::cerr << indentStr << "HeirExactTokenAmounts() will check if this vinx is the tokenbase tokenid=" << tokenid.GetHex() << std::endl; - } - - // checking that the vout of the vintx (that is, referenced by this vin), in its turn, is fed by either from heir' or assets' cryptocondition address: - //std::cerr << indentStr << "HeirExactTokenAmounts() calling IsHeirvout for vintx i=" << i << " prevout.n=" << tx.vin[i].prevout.n << std::endl; - - assetValIndentSize++; - assetoshis = IsHeirvout(compareTotals, cpHeir, eval, tokenid, vinTx, tx.vin[i].prevout.n); - assetValIndentSize--; - if (assetoshis > 0) - inputs += assetoshis; - } - } - } - for (int32_t i = 0; iInvalid("mismatched inputs != outputs + txfee") : false; - } - else { - //std::cerr << indentStr << "HeirExactTokenAmounts() inputs=" << inputs << " vs outputs=" << outputs << " return true" << std::endl; - return(true); - } -}*/ - - -// claim coins tokens validation runner -// sadly we cannot have yet 'templatized' lambdas, if we could we could capture all these params inside HeirValidation() -template bool RunValidationPlans(uint8_t funcId, struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint256 latestTxid, CScript fundingOpretScript, bool isHeirSpendingBegan) +// Plan validation runner, it may be called twice - for coins and tokens +// (sadly we cannot have yet 'templatized' lambdas, if we could we could capture all these params inside HeirValidation()...) +template bool RunValidationPlans(uint8_t funcId, struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint256 latestTxid, CScript fundingOpretScript, uint8_t isHeirSpendingBegan) { int32_t numvins = tx.vin.size(); int32_t numvouts = tx.vout.size(); @@ -176,26 +51,20 @@ template bool RunValidationPlans(uint8_t funcId, struct CCcont CCCInputIdentifier ccInputIdentifier(cp); // vin and vout 'validators' - // always check coin inputs: - CMyPubkeyVoutValidator normalInputValidator(cp, fundingOpretScript, true); // check normal input for this opret cause this is first tx - //CMyPubkeyVoutValidator normalInputValidatorLast(cp, latestTxOpRetScript, true); // check normal input for latest opret. TODO: we may also check this opret - - CCC1of2AddressValidator cc1of2ValidatorThis(cp, fundingOpretScript, "checking this tx opreturn:"); // 1of2add validator with pubkeys from this tx opreturn - //CCC1of2AddressValidator cc1of2ValidatorLast(cp, latestTxOpRetScript, "checking last tx opreturn:"); // 1of2add validator with pubkeys from last tx opreturn + // not used, too strict for 2 pubkeys: CMyPubkeyVoutValidator normalInputValidator(cp, fundingOpretScript, true); // check normal input for this opret cause this is first tx + CCC1of2AddressValidator cc1of2ValidatorThis(cp, fundingOpretScript, "checking this tx opreturn:"); // 1of2add validator with pubkeys from this tx opreturn CHeirSpendValidator heirSpendValidator(cp, fundingOpretScript, latestTxid, isHeirSpendingBegan); // check if heir allowed to spend // only for tokens: - CMyPubkeyVoutValidator ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret - //CMyPubkeyVoutValidator ownerCCaddrValidatorLast(cp, latestTxOpRetScript, false); // check if this correct owner's cc user addr corresponding to lastest opret - // TODO: we may also check with current opret - COpRetValidator opRetValidator(cp, fundingOpretScript); // compare opRets in this and last tx + CMyPubkeyVoutValidator ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret + COpRetValidator opRetValidator(cp, fundingOpretScript); // compare opRets in this and last tx + CNullValidator nullValidator(cp); switch (funcId) { case 'F': // fund tokens // vin validation plan: - // we need cast here this is casted inside - vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &normalInputValidator); // txfee - see AddNormalInput parameter - vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr + vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin + vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr // vout validation plan: voutPlan.pushValidators(0, &cc1of2ValidatorThis); // check 1of2 addr funding @@ -205,22 +74,20 @@ template bool RunValidationPlans(uint8_t funcId, struct CCcont case 'A': // add tokens // vin validation plan: - // we need cast here this is casted inside - vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &normalInputValidator/*, &normalInputValidatorLast*/); // txfee - see AddNormalInput parameter - vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr + vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin + vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr - // vout validation plan: + // vout validation plan: voutPlan.pushValidators(0, &cc1of2ValidatorThis); // check 1of2 addr funding - // do not check change at this time - voutPlan.pushValidators(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A: + // do not check change at this time + voutPlan.pushValidators(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A: break; case 'C': // vin validation plan: - // we need cast here this is casted inside - vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &normalInputValidator/*&normalInputValidatorLast*/); // txfee - see AddNormalInput parameter - vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &cc1of2ValidatorThis /*, &cc1of2ValidatorLast*/); // cc1of2 funding addr - + vinPlan.pushValidators((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin + vinPlan.pushValidators((CInputIdentifierBase*)&ccInputIdentifier, &cc1of2ValidatorThis); // cc1of2 funding addr + // vout validation plan: voutPlan.pushValidators(0, &heirSpendValidator); // check if heir is allowed to spend voutPlan.pushValidators(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A @@ -239,33 +106,34 @@ template bool RunValidationPlans(uint8_t funcId, struct CCcont /** * Tx validation entry function */ -bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint32_t nIn) +bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction& tx, uint32_t nIn) { int32_t numvins = tx.vin.size(); int32_t numvouts = tx.vout.size(); //int32_t preventCCvins = -1; //int32_t preventCCvouts = -1; + struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + if (numvouts < 1) return eval->Invalid("no vouts"); - if (chainActive.Height() < 741) - return true; + //if (chainActive.Height() < 741) + // return true; uint8_t funcId; - uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, tokenid = zeroid; + uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenid = zeroid; - //CScript opRetScript = tx.vout[numvouts - 1].scriptPubKey; - CScript fundingTxOpRetScript; - bool isHeirSpendingBegan = false; + uint8_t isHeirSpendingBegan = 0, dummyIsHeirSpendingBegan; int32_t heirType = NOT_HEIR; - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, true); + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); if(funcId != 0) heirType = HEIR_COINS; else { - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, false); + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, false); if (funcId != 0) heirType = HEIR_TOKENS; } @@ -278,7 +146,7 @@ bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx return eval->Invalid("invalid tx opreturn format: no fundingtxid present"); } if (heirType == HEIR_COINS) - latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, isHeirSpendingBegan); + latestTxid = FindLatestFundingTx(fundingTxidInOpret, dummyTokenid, fundingTxOpRetScript, isHeirSpendingBegan); else latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, isHeirSpendingBegan); @@ -290,11 +158,7 @@ bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx fundingTxOpRetScript = tx.vout[numvouts - 1].scriptPubKey; } - // validate prev tx cc inputs = outputs: - /* if (heirType == HEIR_TOKENS && funcId == 't' && !HeirExactTokenAmounts(true, cp, eval, zeroid, tx)) { - std::cerr << "HeirValidate() this tx or some of its vin tx has invalid cc amounts" << std::endl; - return eval->Invalid("this tx or some of its vin tx has invalid cc amounts"); - } */ + std::cerr << "HeirValidate funcid=" << (char)funcId << std::endl; switch (funcId) { case 'F': @@ -315,7 +179,7 @@ bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx // vout.2: normal change // vout.n-1: opreturn 't' tokenid 'F' ownerpk heirpk inactivitytime heirname tokenid if (heirType == HEIR_TOKENS) - return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); else return eval->Invalid("unexpected HeirValidate for heirfund"); // break; @@ -336,7 +200,7 @@ bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx // vout.1: normal change // vout.n-1: opreturn 't' tokenid 'A' ownerpk heirpk inactivitytime fundingtx if (heirType == HEIR_TOKENS) - return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); else return eval->Invalid("unexpected HeirValidate for heiradd"); //break; @@ -360,9 +224,9 @@ bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx // vout.2: change to normal from txfee input if any // vout.n-1: opreturn 't' tokenid 'C' ownerpk heirpk inactivitytime fundingtx if (heirType == HEIR_TOKENS) - return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); else - return RunValidationPlans(funcId, cp, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpHeir, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); // break; default: @@ -383,13 +247,15 @@ bool HeirValidate(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx */ int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, int32_t voutIndex, CPubKey ownerPubkey, CPubKey heirPubkey) { - char destaddr[65], heirContractAddr[65]; + char destaddr[65], heirFundingAddr[65]; - GetCCaddress1of2(cp, heirContractAddr, ownerPubkey, heirPubkey); + GetCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey); if (tx.vout[voutIndex].scriptPubKey.IsPayToCryptoCondition() != 0) { // NOTE: dimxy it was unsafe 'Getscriptaddress(destaddr,tx.vout[voutIndex].scriptPubKey) > 0' here: - if (Getscriptaddress(destaddr, tx.vout[voutIndex].scriptPubKey) && strcmp(destaddr, heirContractAddr) == 0) + if (Getscriptaddress(destaddr, tx.vout[voutIndex].scriptPubKey) && strcmp(destaddr, heirFundingAddr) == 0) return (tx.vout[voutIndex].nValue); + else + std::cerr << "IsHeirFundingVout() heirFundingAddr=" << heirFundingAddr << " not equal to destaddr=" << destaddr << std::endl; } return (0); } @@ -437,30 +303,19 @@ CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirP { uint8_t evalcode = EVAL_HEIR; - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName); + return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName); } // makes coin additional tx opret -CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid) +CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { uint8_t evalcode = EVAL_HEIR; fundingtxid = revuint256(fundingtxid); - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)funcid << fundingtxid); + return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << isHeirSpendingBegan); } // makes opret for tokens while they are inside Heir contract address space - initial funding -CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) -{ - uint8_t evalcode = EVAL_TOKENS; - uint8_t ccType = 0; - if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) - ccType = voutPubkeys.size(); - - tokenid = revuint256(tokenid); - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)'t' << tokenid << (uint8_t)funcid << ccType; if (ccType >= 1) ss << voutPubkeys[0]; if (ccType == 2) ss << voutPubkeys[1]; ss << ownerPubkey << heirPubkey << inactivityTimeSec << hearName); -} -// makes opret for tokens while they are inside Heir contract address space - additional funding -CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid) +CScript EncodeHeirTokensCreateOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) { uint8_t evalcode = EVAL_HEIR; uint8_t ccType = 0; @@ -468,16 +323,43 @@ CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector= 1) ss << voutPubkeys[0]; \ + if (ccType == 2) ss << voutPubkeys[1]; \ + ss << heirFuncId << ownerPubkey << heirPubkey << inactivityTimeSec << hearName); +} +// makes opret for tokens while they are inside Heir contract address space - additional funding +CScript EncodeHeirTokensOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) +{ + uint8_t evalcode = EVAL_HEIR; + uint8_t ccType = 0; + if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) + ccType = voutPubkeys.size(); + + tokenid = revuint256(tokenid); // for visualization in debug logs fundingtxid = revuint256(fundingtxid); - return CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalcode << (uint8_t)'t' << tokenid << ccType; if (ccType >= 1) ss << voutPubkeys[0]; if (ccType == 2) ss << voutPubkeys[1]; ss << (uint8_t)funcid << fundingtxid); + return CScript() << OP_RETURN << + E_MARSHAL(ss << evalcode << (uint8_t)'t' << tokenid << ccType; \ + if (ccType >= 1) ss << voutPubkeys[0]; \ + if (ccType == 2) ss << voutPubkeys[1]; \ + ss << heirFuncId << fundingtxid << isHeirSpendingBegan); } // helper for decode heir opret payload // NOTE: Heir for coins has the same opret as Heir for tokens -uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret) { +uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &isHeirSpendingBegan) { uint8_t heirFuncId = 0; + isHeirSpendingBegan = 0; + + bool result = E_UNMARSHAL(vopretExtra, { ss >> heirFuncId; \ + if( heirFuncId == 'F') { \ + ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; \ + } else { \ + ss >> fundingTxidInOpret >> isHeirSpendingBegan; \ + } \ + }); - bool result = E_UNMARSHAL(vopretExtra, { ss >> heirFuncId; ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; if (IS_CHARINSTR(heirFuncId, "F")) { ss >> heirName; } if (IS_CHARINSTR(heirFuncId, "AC")) { ss >> fundingTxidInOpret; } }); if (!result /*|| assetFuncId != 't' -- any tx is ok*/) return (uint8_t)0; @@ -486,11 +368,11 @@ uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, /** * decode opret vout for Heir contract */ -template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, bool noLogging) +template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &isHeirSpendingBegan, bool noLogging) { - uint8_t evalCodeInOpret = 0; std::vector vopretExtra; + uint8_t evalCodeInOpret = 0; uint256 dummyTokenid; std::vector voutPubkeysDummy; @@ -498,36 +380,50 @@ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 & tokenid = zeroid; - // First - decode token opret: - uint8_t funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra); + if (typeid(Helper) == typeid(TokenHelper)) { // if caller thinks it is a token - //GetOpReturnData(scriptPubKey, vopret); - - if (funcId != 0 && vopretExtra.size() > 1) { // TODO: add this funcId cond in Assets too - // NOTE: it unmarshals for all F, A and C - uint8_t heirFuncId = _UnmarshalOpret(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret); - - /* - std::cerr << "DecodeHeirOpRet() e=" << (int)e - << " funcId=" << (char)funcId - << " ownerPubkey=" << HexStr(ownerPubkey) - << " heirPubkey=" << HexStr(heirPubkey) - << " heirName=" << heirName << " inactivityTime=" << inactivityTime << '\n'; - */ - - //if (e == EVAL_HEIR && IS_CHARINSTR(funcId, "FAC")) - if (evalCodeInOpret == EVAL_HEIR && Helper::isMyFuncId(heirFuncId)) { - tokenid = revuint256(tokenid); - fundingTxidInOpret = revuint256(fundingTxidInOpret); - return heirFuncId; - } - else - { - if(!noLogging) std::cerr << "DecodeHeirOpRet() warning unexpected OP_RETURN eval=" << (int)evalCodeInOpret << " or field type=" << (char)(heirFuncId ? heirFuncId : ' ') << '\n'; + // First - decode token opret: + uint8_t tokenFuncId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra); + if (tokenFuncId == 0) { + if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: not heir token opret, tokenFuncId=" << (int)tokenFuncId << std::endl; + return (uint8_t)0; } } else { - std::cerr << "DecodeHeirOpRet() unmarshal error (vopret.size() == 0)" << '\n'; + std::vector vopret; + + GetOpReturnData(scriptPubKey, vopret); + if (vopret.size() == 0) { + if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl; + return (uint8_t)0; + } + evalCodeInOpret = vopret.begin()[0]; + vopretExtra = std::vector( vopret.begin()+1, vopret.end() ); // vopretExtra = vopret + 1, get it for futher parsing + } + + if (vopretExtra.size() > 1 && evalCodeInOpret == EVAL_HEIR) { + // NOTE: it unmarshals for all F, A and C + uint8_t heirFuncId = _UnmarshalOpret(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, isHeirSpendingBegan); + + /*std::cerr << "DecodeHeirOpRet()" + << " heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') + << " ownerPubkey=" << HexStr(ownerPubkey) + << " heirPubkey=" << HexStr(heirPubkey) + << " heirName=" << heirName << " inactivityTime=" << inactivityTime + << " isHeirSpendingBegan=" << (int)isHeirSpendingBegan << std::endl;*/ + + + //if (e == EVAL_HEIR && IS_CHARINSTR(funcId, "FAC")) + if (Helper::isMyFuncId(heirFuncId)) { + fundingTxidInOpret = revuint256(fundingTxidInOpret); + return heirFuncId; + } + else { + if(!noLogging) std::cerr << "DecodeHeirOpRet() error: unexpected opret, heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << std::endl; + } + } + else { + if (!noLogging) std::cerr << "DecodeHeirOpRet() error: not a heir opret, vopretExtra.size() == 0 or not EVAL_HEIR evalcode=" << (int)evalCodeInOpret << std::endl; } return (uint8_t)0; } @@ -538,20 +434,21 @@ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 & template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { uint256 dummytxid; + uint8_t dummyIsHeirSpendingBegan; - return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, noLogging); + return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyIsHeirSpendingBegan, noLogging); } /** * overload for A, C oprets and AddHeirContractInputs */ -template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxidInOpret, bool noLogging) +template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxidInOpret, uint8_t &isHeirSpendingBegan, bool noLogging) { CPubKey dummyOwnerPubkey, dummyHeirPubkey; int64_t dummyInactivityTime; std::string dummyHeirName; - return _DecodeHeirOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, noLogging); + return _DecodeHeirOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, isHeirSpendingBegan, noLogging); } @@ -560,7 +457,7 @@ template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &t * find the latest funding tx: it may be the first F tx or one of A or C tx's * Note: this function is also called from validation code (use non-locking calls) */ -template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, bool &isHeirSpendingBegan) +template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &isHeirSpendingBegan) { CTransaction fundingtx; uint256 hashBlock; @@ -570,8 +467,8 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ //CCtxidaddr(markeraddr, fundingtxid); //SetCCunspents(unspentOutputs, markeraddr); - isHeirSpendingBegan = false; //init the var - funcId = 0; //init the var + isHeirSpendingBegan = 0; + funcId = 0; // get initial funding tx and set it as initial lasttx: if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { @@ -580,7 +477,7 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ // set ownerPubkey and heirPubkey: if ((funcId = DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) != 0) { // found at least funding tx! - std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n'; + //std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n'; fundingOpretScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; } else { std::cerr << "FindLatestFundingTx() could not decode opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n'; @@ -616,37 +513,33 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ //NOTE: maybe called from validation code: if (myGetTransaction(txid, regtx, hash)) { - std::cerr << "FindLatestFundingTx() found tx for txid=" << txid.GetHex() << " blockHeight=" << blockHeight << " maxBlockHeight=" << maxBlockHeight << '\n'; + //std::cerr << "FindLatestFundingTx() found tx for txid=" << txid.GetHex() << " blockHeight=" << blockHeight << " maxBlockHeight=" << maxBlockHeight << '\n'; - { // debug code: + /*{ // debug code: uint256 debAssetid; - uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, true); - std::cerr << "FindLatestFundingTx() regtx.vout.size()=" << regtx.vout.size() << " funcId=" << (char)(debfuncid ? debfuncid : ' ') << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << std::endl; - } + uint8_t debIsHeirSpendingBegan; + uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, debIsHeirSpendingBegan, true); + + std::cerr << "FindLatestFundingTx() regtx.vout.size()=" << regtx.vout.size() << " funcId=" << (char)(debfuncid ? debfuncid : ' ') + << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << " debIsHeirSpendingBegan=" << (int)debIsHeirSpendingBegan << std::endl; + }*/ uint256 dummyTokenid; // not to contaminate the tokenid from the params! uint8_t tmpFuncId; + uint8_t tmpIsHeirSpendingBegan; if (regtx.vout.size() > 0 && - (tmpFuncId = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, true)) != 0 && + (tmpFuncId = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, tmpIsHeirSpendingBegan, true)) != 0 && fundingtxid == fundingTxidInOpret) { - // check if heir has begun spending: - if (Helper::isSpendingTx(tmpFuncId)) { // if 'C' or 't' opret - const CScript heirScriptPubkey = CScript() << ParseHex(HexStr(heirPubkey)) << OP_CHECKSIG; - - for (int32_t v = 0; v < regtx.vout.size() - 1; v++) { // do not check opret vout - if (heirScriptPubkey == regtx.vout[v].scriptPubKey) - isHeirSpendingBegan = true; - } - } - if (blockHeight > maxBlockHeight) { maxBlockHeight = blockHeight; latesttxid = txid; - ///// fundingOpretScript = regtx.vout[regtx.vout.size() - 1].scriptPubKey; funcId = tmpFuncId; - std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight << " opreturn type=" << (char)(funcId ? funcId : ' ') << " set as current lasttxid" << '\n'; + isHeirSpendingBegan = tmpIsHeirSpendingBegan; + + //std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight + // << " opreturn type=" << (char)(funcId ? funcId : ' ') << " isHeirSpendingBegan=" << (int)isHeirSpendingBegan << " - set as current lasttxid" << '\n'; } } } @@ -656,7 +549,7 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ } // overload for validation code -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, bool &isHeirSpendingBegan) +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan) { uint8_t funcId; CPubKey ownerPubkey; @@ -668,81 +561,19 @@ template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 } // overload for transaction creation code -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool &isHeirSpendingBegan) +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &isHeirSpendingBegan) { CScript opRetScript; return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, isHeirSpendingBegan); } -// add owner input in tokens -/*int64_t AddHeirTokenInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 refassetid, int64_t total, int32_t maxinputs) -{ - char coinaddr[64], destaddr[64]; int64_t threshold, nValue, price, totalinputs = 0; uint256 tokenid, txid, hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j, vout, n = 0; uint8_t evalcode, funcid; - std::vector > unspentOutputs; - GetCCaddress(cp, coinaddr, pk); - SetCCunspents(unspentOutputs, coinaddr); - threshold = total / (maxinputs + 1); - - //fprintf(stderr,"AddHeirTokenInputs() check cc addr=%s for token inputs\n",coinaddr); - for (std::vector >::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) - { - txid = it->first.txhash; - vout = (int32_t)it->first.index; - - if (it->second.satoshis < threshold) - continue; - for (j = 0; jsecond=" << it->second.satoshis << std::endl; - - if (strcmp(destaddr, coinaddr) != 0 && strcmp(destaddr, cp->unspendableCCaddr) != 0 && strcmp(destaddr, cp->unspendableaddr2) != 0) - continue; - GetOpReturnData(vintx.vout[vintx.vout.size() - 1].scriptPubKey, vopret); - - // NOTE: special opret decode: - // we should not check for E_UNMARSHAL return code because it returns false if not EOF, - // but we have our remainder after tokenid! - bool isEof = false; - bool unmarshalResult = E_UNMARSHAL(vopret, ss >> evalcode; ss >> funcid; ss >> tokenid; isEof=ss.eof()); - if (unmarshalResult || !isEof) - { - tokenid = revuint256(tokenid); // usually DecodeOpretXXX() funcs do this - - //std::cerr << "AddHeirTokenInputs() vout=" << vout << " evalcode=" << (int)evalcode << " cp->evalcode=" << (int)cp->evalcode << " funcid=" << (char)funcid << " check for refassetid=" << refassetid.GetHex() << " vs tokenid in opret=" << tokenid.GetHex() << " coins=" << (double)vintx.vout[vout].nValue / COIN << std::endl; - if (tokenid == refassetid && - IS_CHARINSTR(funcid, "tGB") && - (nValue = vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) - { - std::cerr << "AddHeirTokenInputs() total=" << total << " maxinputs=" << maxinputs << " uxto value=" << it->second.satoshis << std::endl; - if (total != 0 && maxinputs != 0) - mtx.vin.push_back(CTxIn(txid, vout, CScript())); - //nValue = it->second.satoshis; - totalinputs += nValue; - n++; - if ((total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs)) - break; - } - } - } - } - return(totalinputs); -}*/ - // add inputs of 1 of 2 cc address template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, uint256 fundingtxid, CMutableTransaction& mtx, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t total, int32_t maxinputs) { // TODO: add threshold check int64_t nValue, voutValue, totalinputs = 0; - CTransaction vintx; + CTransaction heirtx; int32_t n = 0; std::vector> unspentOutputs; @@ -753,7 +584,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, // char markeraddr[64]; // CCtxidaddr(markeraddr, fundingtxid); // SetCCunspents(unspentOutputs, markeraddr); - //std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; + // std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << std::endl; for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { uint256 txid = it->first.txhash; @@ -761,21 +592,20 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, int32_t voutIndex = (int32_t)it->first.index; // no need to prevent dup // dimxy: maybe it is good to put tx's in cache? - if (GetTransaction(txid, vintx, hashBlock, false) != 0) { + if (GetTransaction(txid, heirtx, hashBlock, false) != 0) { uint256 tokenid; uint256 fundingTxidInOpret; - - uint8_t funcId = DecodeHeirOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, true); - // note: it returns in in satoshis too... - if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && // we're spending only tx's in this funding plan - funcId != 0 && + uint8_t dummyIsHeirSpendingBegan; + + uint8_t funcId = DecodeHeirOpRet(heirtx.vout[heirtx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); + if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && + funcId != 0 && Helper::isMyFuncId(funcId) && - // deep validation for tokens: - (typeid(Helper) == typeid(TokenHelper) && IsHeirvout(true, cp, nullptr, tokenid, vintx, voutIndex) > 0) && - (voutValue = IsHeirFundingVout(cp, vintx, voutIndex, ownerPubkey, heirPubkey)) > 0 && + // (typeid(Helper) == typeid(TokenHelper) && IsHeirvout(true, cp, nullptr, tokenid, vintx, voutIndex) > 0) && // deep validation for tokens - not used anymore + (voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && !myIsutxo_spentinmempool(txid, voutIndex)) { - std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; + //std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; if (total != 0 && maxinputs != 0) mtx.vin.push_back(CTxIn(txid, voutIndex, CScript())); nValue = it->second.satoshis; @@ -812,8 +642,9 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info uint256 tokenid; uint256 fundingTxidInOpret; const int32_t ivout = 0; + uint8_t dummyIsHeirSpendingBegan; - funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, true); + funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); //std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n'; @@ -821,7 +652,7 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info /* && !myIsutxo_spentinmempool(txid, ccVoutIdx) */) // include also tx in mempool { total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change) - std::cerr << "LifetimeHeirContractFunds() added tx=" << txid.GetHex() << " it->second=" << it->second << " vout[0].nValue=" << tx.vout[ivout].nValue << " opreturn=" << (char)funcId << '\n'; + //std::cerr << "LifetimeHeirContractFunds() added tx=" << txid.GetHex() << " it->second=" << it->second << " vout[0].nValue=" << tx.vout[ivout].nValue << " opreturn=" << (char)funcId << '\n'; } } } @@ -920,9 +751,10 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in uint256 lasttxid, tokenid; std::string heirName; uint8_t funcId; - bool isHeirSpendingBegan = false; + uint8_t isHeirSpendingBegan = 0; cp = CCinit(&C, Helper::getMyEval()); + if (txfee == 0) txfee = 10000; @@ -942,7 +774,6 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in int64_t inputs, change; - //if (AddNormalinputs(mtx, myPubkey, amount + 1 * txfee, 64) > 0) { // TODO: why 64 max inputs? if ((inputs = Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, 64)) > 0) { // TODO: why 64 max inputs? // we do not use markers anymore - storing data in opreturn is better @@ -955,7 +786,6 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in // add cryptocondition to spend this funded amount for either pk mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), amount, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! - // calc and add change vout: if (inputs > amount) change = (inputs - amount); // -txfee <-- txfee pays user @@ -972,7 +802,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in // add opreturn 'A' and sign tx: // this txfee ignored std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid))); + Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan))); result.push_back(Pair("result", "success")); result.push_back(Pair("hextx", rawhextx)); @@ -1025,7 +855,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee uint256 latesttxid, tokenid; uint8_t funcId; std::string heirName; - bool isHeirSpendingBegan = false; + uint8_t isHeirSpendingBegan = 0; cp = CCinit(&C, Helper::getMyEval()); @@ -1117,7 +947,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee // add opreturn 'C' and sign tx: // this txfee will be ignored std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid)); + Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid, (myPubkey == heirPubkey) ? 1 : isHeirSpendingBegan)); // forward isHeirSpending to the next latest tx result.push_back(Pair("result", "success")); result.push_back(Pair("hextx", rawhextx)); @@ -1181,9 +1011,11 @@ UniValue HeirInfo(uint256 fundingtxid) if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { int32_t heirType = NOT_HEIR; - if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true) == 'F') + const bool noLogging = true; + + if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging) == 'F') heirType = HEIR_COINS; - else if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true) == 'F') + else if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging) == 'F') heirType = HEIR_TOKENS; else { @@ -1199,7 +1031,7 @@ UniValue HeirInfo(uint256 fundingtxid) else cp = CCinit(&C, TokenHelper::getMyEval()); - bool isHeirSpendingBegan = false; + uint8_t isHeirSpendingBegan = 0; if (heirType == HEIR_COINS) latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan); @@ -1210,7 +1042,7 @@ UniValue HeirInfo(uint256 fundingtxid) int32_t numblocks; uint64_t durationSec = 0; - std::cerr << "HeirInfo() latesttxid=" << latestFundingTxid.GetHex() << '\n'; + //std::cerr << "HeirInfo() latesttxid=" << latestFundingTxid.GetHex() << '\n'; std::ostringstream stream; std::string msg; @@ -1324,7 +1156,7 @@ template void _HeirList(struct CCcontract_info *cp, UniValue &r GetCCaddress(cp, coinaddr, ccPubKeyEmpty); SetCCunspents(unspentOutputs, cp->normaladdr); - std::cerr << "HeirList() finding heir marker from Heir contract addr=" << cp->normaladdr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; + //std::cerr << "HeirList() finding heir marker from Heir contract addr=" << cp->normaladdr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; // TODO: move marker to special cc addr to prevent checking all tokens for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { @@ -1333,26 +1165,28 @@ template void _HeirList(struct CCcontract_info *cp, UniValue &r uint256 tokenid; int32_t vout = (int32_t)it->first.index; - std::cerr << "HeirList() checking txid=" << txid.GetHex() << " vout=" << vout << '\n'; + //std::cerr << "HeirList() checking txid=" << txid.GetHex() << " vout=" << vout << '\n'; - CTransaction vintx; - if (GetTransaction(txid, vintx, hashBlock, false) != 0 && (vintx.vout.size() - 1) > 0) { + CTransaction inittx; + if (GetTransaction(txid, inittx, hashBlock, false) != 0 && (inittx.vout.size() - 1) > 0) { CPubKey ownerPubkey, heirPubkey; std::string heirName; int64_t inactivityTimeSec; + const bool noLogging = true; - uint8_t funcId = DecodeHeirOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + uint8_t funcId = DecodeHeirOpRet(inittx.vout[inittx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); // note: if it is not Heir token funcId would be equal to 0 if (funcId == 'F') { - result.push_back(Pair("fundingtxid heirName", txid.GetHex() + std::string(" ") + (typeid(Helper) == typeid(TokenHelper) ? std::string("token") : std::string("coin")) + std::string(" ") + heirName)); + //result.push_back(Pair("fundingtxid kind name", txid.GetHex() + std::string(" ") + (typeid(Helper) == typeid(TokenHelper) ? std::string("token") : std::string("coin")) + std::string(" ") + heirName)); + result.push_back( Pair("fundingtxid", txid.GetHex()) ); } else { - fprintf(stderr, "HeirList() couldnt find initial transaction\n"); + std::cerr << "HeirList() this is not the initial F transaction=" << txid.GetHex() << std::endl; } } else { - fprintf(stderr, "HeirList() couldnt load transaction\n"); + std::cerr << "HeirList() could not load transaction=" << txid.GetHex() << std::endl; } } } @@ -1363,10 +1197,10 @@ UniValue HeirList() UniValue result(UniValue::VOBJ); result.push_back(Pair("result", "success")); - struct CCcontract_info *cpHeir, *cpTokens, C; + struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit! - cpHeir = CCinit(&C, EVAL_HEIR); - cpTokens = CCinit(&C, EVAL_TOKENS); + cpHeir = CCinit(&heirC, EVAL_HEIR); + cpTokens = CCinit(&tokenC, EVAL_TOKENS); _HeirList(cpHeir, result); _HeirList(cpTokens, result); diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 108562e24..5b5df2110 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -12,21 +12,15 @@ // makes coin initial tx opret CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); -// makes coin additional tx opret -CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid); - +CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); +// makes token opret CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName); -CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid); -//CScript EncodeHeirConvertedAssetsOpRet(uint8_t eval, uint8_t funcid, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 fundingtxid); +CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan); -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, bool &isHeirSpendingBegan); -template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxid, bool noLogging = false); -//template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan); +template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false); template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); -//int64_t AddHeirTokenInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 reftokenid, int64_t total, int32_t maxinputs); - - // helper class to allow polymorphic behaviour for HeirXXX() functions in case of coins class CoinHelper { public: @@ -40,11 +34,11 @@ public: static CScript makeCreateOpRet(uint256 dummyid, std::vector dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName); } - static CScript makeAddOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid) { - return EncodeHeirOpRet((uint8_t)'A', fundingtxid); + static CScript makeAddOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { + return EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan); } - static CScript makeClaimOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid) { - return EncodeHeirOpRet((uint8_t)'C', fundingtxid); + static CScript makeClaimOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { + return EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan); } static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } @@ -69,11 +63,11 @@ public: static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { return EncodeHeirTokensCreateOpRet((uint8_t)'F', tokenid, voutTokenPubkeys, ownerPubkey, heirPubkey, inactivityTimeSec, heirName); } - static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid) { - return EncodeHeirTokensOpRet((uint8_t)'A', tokenid, voutTokenPubkeys, fundingtxid); + static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { + return EncodeHeirTokensOpRet((uint8_t)'A', tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan); } - static CScript makeClaimOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid) { - return EncodeHeirTokensOpRet((uint8_t)'C', tokenid, voutTokenPubkeys, fundingtxid); + static CScript makeClaimOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { + return EncodeHeirTokensOpRet((uint8_t)'C', tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan); } static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } @@ -86,9 +80,6 @@ public: } }; -//#define OPTIONAL_VOUT 0 // if vout is optional then in a validation plan it will be skipped without error, if all validators return false - - /** * Small framework for vins and vouts validation implementing a variation of 'chain of responsibility' pattern: @@ -104,10 +95,8 @@ public: * * 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 */ + /** * base class for all validators */ @@ -123,7 +112,6 @@ protected: CCcontract_info * m_cp; }; - /** * Base class for classes which identify vins as normal or cc inputs */ @@ -137,9 +125,6 @@ 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 @@ -222,7 +207,7 @@ public: return eval->Invalid("incorrect tx structure: not all required vins are present."); } - std::cerr << "CInputValidationPlan::validate() returns with true" << std::endl; + //std::cerr << "CInputValidationPlan::validate() returns with true" << std::endl; return true; } @@ -246,7 +231,7 @@ private: // 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; + //std::cerr << "CInputValidationPlan::execValidatorsInRow() calling validators" << " for vin iv=" << iv << " ival=" << ival << std::endl; for (auto v : vValidators) { bool result; @@ -327,7 +312,7 @@ public: } - std::cerr << "COutputValidationPlan::validate() returns with true" << std::endl; + //std::cerr << "COutputValidationPlan::validate() returns with true" << std::endl; return true; } @@ -351,7 +336,7 @@ private: // 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; + //std::cerr << "COutputValidationPlan::execRow() calling validators" << " for vout iv=" << iv << " ival=" << ival << std::endl; for (auto v : vValidators) { @@ -422,7 +407,7 @@ public: GetCCaddress1of2(m_cp, 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; + //std::cerr << "CCC1of2AddressValidator::validateVout() exits with true" << std::endl; return true; } else { @@ -476,23 +461,24 @@ public: if (m_checkNormals) { 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; } - //std::cerr << "CMyPubkeyVoutValidator::validateVout() vout.scriptPubKey=" << vout.scriptPubKey.ToString() << " makeUserVout=" << Helper::makeUserVout(vout.nValue, ownerPubkey).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; + //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, CTxOut prevVout, std::string& message) const { return true; } @@ -509,7 +495,7 @@ private: template class CHeirSpendValidator : CValidatorBase { public: - CHeirSpendValidator(CCcontract_info* cp, CScript opRetScript, uint256 latesttxid, bool isHeirSpendingBegan) + 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; } @@ -547,7 +533,7 @@ public: } } - std::cerr << "CHeirSpendValidator::validateVout() exits with true" << std::endl; + //std::cerr << "CHeirSpendValidator::validateVout() exits with true" << std::endl; // this is not heir: return true; @@ -557,7 +543,7 @@ public: private: CScript m_fundingOpretScript; uint256 m_latesttxid; - bool m_isHeirSpendingBegan; + uint8_t m_isHeirSpendingBegan; }; /** @@ -576,12 +562,13 @@ public: uint8_t funcId, initialFuncId; // do not check heir name uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid, initialTokenid; + uint8_t dummyIsHeirSpendingBegan; - if ((funcId = DecodeHeirOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret)) == 0) { + if ((funcId = DecodeHeirOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan)) == 0) { message = std::string("invalid opreturn format"); return false; } - if ((initialFuncId = DecodeHeirOpRet(m_fundingOpretScript, initialTokenid, dummyTxid)) == 0) { + if ((initialFuncId = DecodeHeirOpRet(m_fundingOpretScript, initialTokenid, dummyTxid, dummyIsHeirSpendingBegan)) == 0) { message = std::string("invalid initial tx opreturn format"); return false; } @@ -606,6 +593,19 @@ private: CScript m_fundingOpretScript; }; +/** +* 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, std::string& message) const { return true; } + virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; } +}; #endif \ No newline at end of file From 8e8d4e0057313fb94ad0ee880faf0e21775a6504 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 9 Jan 2019 17:19:49 +0500 Subject: [PATCH 009/106] improved heir spending var name --- src/cc/heir.cpp | 110 ++++++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index d75580cec..ad71b3b2a 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -36,7 +36,7 @@ class TokenHelper; // Plan validation runner, it may be called twice - for coins and tokens // (sadly we cannot have yet 'templatized' lambdas, if we could we could capture all these params inside HeirValidation()...) -template bool RunValidationPlans(uint8_t funcId, struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint256 latestTxid, CScript fundingOpretScript, uint8_t isHeirSpendingBegan) +template bool RunValidationPlans(uint8_t funcId, struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, uint256 latestTxid, CScript fundingOpretScript, uint8_t hasHeirSpendingBegun) { int32_t numvins = tx.vin.size(); int32_t numvouts = tx.vout.size(); @@ -53,7 +53,7 @@ template bool RunValidationPlans(uint8_t funcId, struct CCcont // vin and vout 'validators' // not used, too strict for 2 pubkeys: CMyPubkeyVoutValidator normalInputValidator(cp, fundingOpretScript, true); // check normal input for this opret cause this is first tx CCC1of2AddressValidator cc1of2ValidatorThis(cp, fundingOpretScript, "checking this tx opreturn:"); // 1of2add validator with pubkeys from this tx opreturn - CHeirSpendValidator heirSpendValidator(cp, fundingOpretScript, latestTxid, isHeirSpendingBegan); // check if heir allowed to spend + CHeirSpendValidator heirSpendValidator(cp, fundingOpretScript, latestTxid, hasHeirSpendingBegun); // check if heir allowed to spend // only for tokens: CMyPubkeyVoutValidator ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret @@ -126,14 +126,14 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenid = zeroid; CScript fundingTxOpRetScript; - uint8_t isHeirSpendingBegan = 0, dummyIsHeirSpendingBegan; + uint8_t hasHeirSpendingBegun = 0, dummyhasHeirSpendingBegun; int32_t heirType = NOT_HEIR; - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, true); if(funcId != 0) heirType = HEIR_COINS; else { - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, false); + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, false); if (funcId != 0) heirType = HEIR_TOKENS; } @@ -146,9 +146,9 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction return eval->Invalid("invalid tx opreturn format: no fundingtxid present"); } if (heirType == HEIR_COINS) - latestTxid = FindLatestFundingTx(fundingTxidInOpret, dummyTokenid, fundingTxOpRetScript, isHeirSpendingBegan); + latestTxid = FindLatestFundingTx(fundingTxidInOpret, dummyTokenid, fundingTxOpRetScript, hasHeirSpendingBegun); else - latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, isHeirSpendingBegan); + latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, hasHeirSpendingBegun); if (latestTxid == zeroid) { return eval->Invalid("invalid heir transaction: no funding tx found"); @@ -179,7 +179,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction // vout.2: normal change // vout.n-1: opreturn 't' tokenid 'F' ownerpk heirpk inactivitytime heirname tokenid if (heirType == HEIR_TOKENS) - return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); else return eval->Invalid("unexpected HeirValidate for heirfund"); // break; @@ -200,7 +200,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction // vout.1: normal change // vout.n-1: opreturn 't' tokenid 'A' ownerpk heirpk inactivitytime fundingtx if (heirType == HEIR_TOKENS) - return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); else return eval->Invalid("unexpected HeirValidate for heiradd"); //break; @@ -224,9 +224,9 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction // vout.2: change to normal from txfee input if any // vout.n-1: opreturn 't' tokenid 'C' ownerpk heirpk inactivitytime fundingtx if (heirType == HEIR_TOKENS) - return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); else - return RunValidationPlans(funcId, cpHeir, eval, tx, latestTxid, fundingTxOpRetScript, isHeirSpendingBegan); + return RunValidationPlans(funcId, cpHeir, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); // break; default: @@ -307,12 +307,12 @@ CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirP } // makes coin additional tx opret -CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan) +CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpendingBegun) { uint8_t evalcode = EVAL_HEIR; fundingtxid = revuint256(fundingtxid); - return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << isHeirSpendingBegan); + return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun); } // makes opret for tokens while they are inside Heir contract address space - initial funding CScript EncodeHeirTokensCreateOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) @@ -330,7 +330,7 @@ CScript EncodeHeirTokensCreateOpRet(uint8_t heirFuncId, uint256 tokenid, std::ve ss << heirFuncId << ownerPubkey << heirPubkey << inactivityTimeSec << hearName); } // makes opret for tokens while they are inside Heir contract address space - additional funding -CScript EncodeHeirTokensOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) +CScript EncodeHeirTokensOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t hasHeirSpendingBegun) { uint8_t evalcode = EVAL_HEIR; uint8_t ccType = 0; @@ -343,20 +343,20 @@ CScript EncodeHeirTokensOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector= 1) ss << voutPubkeys[0]; \ if (ccType == 2) ss << voutPubkeys[1]; \ - ss << heirFuncId << fundingtxid << isHeirSpendingBegan); + ss << heirFuncId << fundingtxid << hasHeirSpendingBegun); } // helper for decode heir opret payload // NOTE: Heir for coins has the same opret as Heir for tokens -uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &isHeirSpendingBegan) { +uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun) { uint8_t heirFuncId = 0; - isHeirSpendingBegan = 0; + hasHeirSpendingBegun = 0; bool result = E_UNMARSHAL(vopretExtra, { ss >> heirFuncId; \ if( heirFuncId == 'F') { \ ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; \ } else { \ - ss >> fundingTxidInOpret >> isHeirSpendingBegan; \ + ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \ } \ }); @@ -368,7 +368,7 @@ uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, /** * decode opret vout for Heir contract */ -template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &isHeirSpendingBegan, bool noLogging) +template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { std::vector vopretExtra; @@ -403,14 +403,14 @@ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 & if (vopretExtra.size() > 1 && evalCodeInOpret == EVAL_HEIR) { // NOTE: it unmarshals for all F, A and C - uint8_t heirFuncId = _UnmarshalOpret(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, isHeirSpendingBegan); + uint8_t heirFuncId = _UnmarshalOpret(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun); /*std::cerr << "DecodeHeirOpRet()" << " heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << " ownerPubkey=" << HexStr(ownerPubkey) << " heirPubkey=" << HexStr(heirPubkey) << " heirName=" << heirName << " inactivityTime=" << inactivityTime - << " isHeirSpendingBegan=" << (int)isHeirSpendingBegan << std::endl;*/ + << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << std::endl;*/ //if (e == EVAL_HEIR && IS_CHARINSTR(funcId, "FAC")) @@ -434,21 +434,21 @@ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 & template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { uint256 dummytxid; - uint8_t dummyIsHeirSpendingBegan; + uint8_t dummyhasHeirSpendingBegun; - return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyIsHeirSpendingBegan, noLogging); + return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyhasHeirSpendingBegun, noLogging); } /** * overload for A, C oprets and AddHeirContractInputs */ -template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxidInOpret, uint8_t &isHeirSpendingBegan, bool noLogging) +template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { CPubKey dummyOwnerPubkey, dummyHeirPubkey; int64_t dummyInactivityTime; std::string dummyHeirName; - return _DecodeHeirOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, isHeirSpendingBegan, noLogging); + return _DecodeHeirOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); } @@ -457,7 +457,7 @@ template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &t * find the latest funding tx: it may be the first F tx or one of A or C tx's * Note: this function is also called from validation code (use non-locking calls) */ -template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &isHeirSpendingBegan) +template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun) { CTransaction fundingtx; uint256 hashBlock; @@ -467,7 +467,7 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ //CCtxidaddr(markeraddr, fundingtxid); //SetCCunspents(unspentOutputs, markeraddr); - isHeirSpendingBegan = 0; + hasHeirSpendingBegun = 0; funcId = 0; // get initial funding tx and set it as initial lasttx: @@ -517,29 +517,29 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ /*{ // debug code: uint256 debAssetid; - uint8_t debIsHeirSpendingBegan; - uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, debIsHeirSpendingBegan, true); + uint8_t debhasHeirSpendingBegun; + uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, debhasHeirSpendingBegun, true); std::cerr << "FindLatestFundingTx() regtx.vout.size()=" << regtx.vout.size() << " funcId=" << (char)(debfuncid ? debfuncid : ' ') - << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << " debIsHeirSpendingBegan=" << (int)debIsHeirSpendingBegan << std::endl; + << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << " debhasHeirSpendingBegun=" << (int)debhasHeirSpendingBegun << std::endl; }*/ uint256 dummyTokenid; // not to contaminate the tokenid from the params! uint8_t tmpFuncId; - uint8_t tmpIsHeirSpendingBegan; + uint8_t tmphasHeirSpendingBegun; if (regtx.vout.size() > 0 && - (tmpFuncId = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, tmpIsHeirSpendingBegan, true)) != 0 && + (tmpFuncId = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, tmphasHeirSpendingBegun, true)) != 0 && fundingtxid == fundingTxidInOpret) { if (blockHeight > maxBlockHeight) { maxBlockHeight = blockHeight; latesttxid = txid; funcId = tmpFuncId; - isHeirSpendingBegan = tmpIsHeirSpendingBegan; + hasHeirSpendingBegun = tmphasHeirSpendingBegun; //std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight - // << " opreturn type=" << (char)(funcId ? funcId : ' ') << " isHeirSpendingBegan=" << (int)isHeirSpendingBegan << " - set as current lasttxid" << '\n'; + // << " opreturn type=" << (char)(funcId ? funcId : ' ') << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << " - set as current lasttxid" << '\n'; } } } @@ -549,7 +549,7 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ } // overload for validation code -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan) +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &hasHeirSpendingBegun) { uint8_t funcId; CPubKey ownerPubkey; @@ -557,15 +557,15 @@ template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 int64_t inactivityTime; std::string heirName; - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, isHeirSpendingBegan); + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); } // overload for transaction creation code -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &isHeirSpendingBegan) +template uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &hasHeirSpendingBegun) { CScript opRetScript; - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, isHeirSpendingBegan); + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); } // add inputs of 1 of 2 cc address @@ -595,9 +595,9 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, if (GetTransaction(txid, heirtx, hashBlock, false) != 0) { uint256 tokenid; uint256 fundingTxidInOpret; - uint8_t dummyIsHeirSpendingBegan; + uint8_t dummyhasHeirSpendingBegun; - uint8_t funcId = DecodeHeirOpRet(heirtx.vout[heirtx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); + uint8_t funcId = DecodeHeirOpRet(heirtx.vout[heirtx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, true); if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && funcId != 0 && Helper::isMyFuncId(funcId) && @@ -642,9 +642,9 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info uint256 tokenid; uint256 fundingTxidInOpret; const int32_t ivout = 0; - uint8_t dummyIsHeirSpendingBegan; + uint8_t dummyhasHeirSpendingBegun; - funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); + funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, true); //std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n'; @@ -751,14 +751,14 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in uint256 lasttxid, tokenid; std::string heirName; uint8_t funcId; - uint8_t isHeirSpendingBegan = 0; + uint8_t hasHeirSpendingBegun = 0; cp = CCinit(&C, Helper::getMyEval()); if (txfee == 0) txfee = 10000; - if ((lasttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan)) != zeroid) { + if ((lasttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { int32_t numblocks; CPubKey myPubkey = pubkey2pk(Mypubkey()); @@ -802,7 +802,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in // add opreturn 'A' and sign tx: // this txfee ignored std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan))); + Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun))); result.push_back(Pair("result", "success")); result.push_back(Pair("hextx", rawhextx)); @@ -855,26 +855,26 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee uint256 latesttxid, tokenid; uint8_t funcId; std::string heirName; - uint8_t isHeirSpendingBegan = 0; + uint8_t hasHeirSpendingBegun = 0; cp = CCinit(&C, Helper::getMyEval()); if (txfee == 0) txfee = 10000; - if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan)) != zeroid) { + if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { int32_t numblocks; uint64_t durationSec = 0; // we do not need to find duration if spending already has begun - if (!isHeirSpendingBegan) { + if (!hasHeirSpendingBegun) { durationSec = CCduration(numblocks, latesttxid); std::cerr << "HeirClaim() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << std::endl; } // spending is allowed if there is already spending tx or inactivity time //bool isAllowedToHeir = (funcId == 'C' || durationSec > inactivityTimeSec) ? true : false; - bool isAllowedToHeir = (isHeirSpendingBegan || durationSec > inactivityTimeSec) ? true : false; + bool isAllowedToHeir = (hasHeirSpendingBegun || durationSec > inactivityTimeSec) ? true : false; myPubkey = pubkey2pk(Mypubkey()); // if it is the heir, check if spending not allowed to heir yet @@ -947,7 +947,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee // add opreturn 'C' and sign tx: // this txfee will be ignored std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid, (myPubkey == heirPubkey) ? 1 : isHeirSpendingBegan)); // forward isHeirSpending to the next latest tx + Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid, (myPubkey == heirPubkey) ? 1 : hasHeirSpendingBegun)); // forward isHeirSpending to the next latest tx result.push_back(Pair("result", "success")); result.push_back(Pair("hextx", rawhextx)); @@ -1031,12 +1031,12 @@ UniValue HeirInfo(uint256 fundingtxid) else cp = CCinit(&C, TokenHelper::getMyEval()); - uint8_t isHeirSpendingBegan = 0; + uint8_t hasHeirSpendingBegun = 0; if (heirType == HEIR_COINS) - latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan); + latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); else - latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, isHeirSpendingBegan); + latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); if (latestFundingTxid != zeroid) { int32_t numblocks; @@ -1119,12 +1119,12 @@ UniValue HeirInfo(uint256 fundingtxid) stream.str(""); stream.clear(); - if (!isHeirSpendingBegan) { // we do not need find duration if the spending already has begun + if (!hasHeirSpendingBegun) { // we do not need find duration if the spending already has begun durationSec = CCduration(numblocks, latestFundingTxid); std::cerr << "HeirInfo() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << '\n'; } - stream << std::boolalpha << (isHeirSpendingBegan || durationSec > inactivityTimeSec); + stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec); result.push_back(Pair("spending allowed for the heir", stream.str().c_str())); stream.str(""); stream.clear(); From 6e353a59a453b1363e0c2c788718d024dbd1bd13 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 9 Jan 2019 17:28:34 +0500 Subject: [PATCH 010/106] more var name hasheirspendingbegun improved --- src/cc/heir.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index ad71b3b2a..7d5ea7cfe 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -126,14 +126,14 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenid = zeroid; CScript fundingTxOpRetScript; - uint8_t hasHeirSpendingBegun = 0, dummyhasHeirSpendingBegun; + uint8_t hasHeirSpendingBegun = 0, dummyHasHeirSpendingBegun; int32_t heirType = NOT_HEIR; - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, true); + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); if(funcId != 0) heirType = HEIR_COINS; else { - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, false); + funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, false); if (funcId != 0) heirType = HEIR_TOKENS; } @@ -434,9 +434,9 @@ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 & template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { uint256 dummytxid; - uint8_t dummyhasHeirSpendingBegun; + uint8_t dummyHasHeirSpendingBegun; - return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyhasHeirSpendingBegun, noLogging); + return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging); } /** @@ -517,11 +517,11 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ /*{ // debug code: uint256 debAssetid; - uint8_t debhasHeirSpendingBegun; - uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, debhasHeirSpendingBegun, true); + uint8_t debHasHeirSpendingBegun; + uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, debHasHeirSpendingBegun, true); std::cerr << "FindLatestFundingTx() regtx.vout.size()=" << regtx.vout.size() << " funcId=" << (char)(debfuncid ? debfuncid : ' ') - << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << " debhasHeirSpendingBegun=" << (int)debhasHeirSpendingBegun << std::endl; + << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << " debHasHeirSpendingBegun=" << (int)debHasHeirSpendingBegun << std::endl; }*/ uint256 dummyTokenid; // not to contaminate the tokenid from the params! @@ -595,9 +595,9 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, if (GetTransaction(txid, heirtx, hashBlock, false) != 0) { uint256 tokenid; uint256 fundingTxidInOpret; - uint8_t dummyhasHeirSpendingBegun; + uint8_t dummyHasHeirSpendingBegun; - uint8_t funcId = DecodeHeirOpRet(heirtx.vout[heirtx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, true); + uint8_t funcId = DecodeHeirOpRet(heirtx.vout[heirtx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && funcId != 0 && Helper::isMyFuncId(funcId) && @@ -642,9 +642,9 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info uint256 tokenid; uint256 fundingTxidInOpret; const int32_t ivout = 0; - uint8_t dummyhasHeirSpendingBegun; + uint8_t dummyHasHeirSpendingBegun; - funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyhasHeirSpendingBegun, true); + funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); //std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n'; From 884c58e3cf341763d8dbadcc844d75d894c4a72f Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 9 Jan 2019 18:04:15 +0500 Subject: [PATCH 011/106] removed test CCerror code --- src/wallet/rpcwallet.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1320da61c..b39a19668 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6952,20 +6952,12 @@ UniValue tokenlist(const UniValue& params, bool fHelp) UniValue tokeninfo(const UniValue& params, bool fHelp) { -#ifdef TESTMODE - std::cerr << "is CCerror clear? CCerror=" << CCerror << std::endl; -#endif uint256 tokenid; if ( fHelp || params.size() != 1 ) throw runtime_error("tokeninfo tokenid\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); tokenid = Parseuint256((char *)params[0].get_str().c_str()); - -#ifdef TESTMODE - CCerror = "test error"; -#endif - return(AssetInfo(tokenid)); } From 1f6d62e7c84a43cbf58a70e82cb1dcd5ec1f196d Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 13:40:21 +0500 Subject: [PATCH 012/106] MakeTokensCC1of2vout MakeTokensCCcond1of2 test code added gateways partially adapted for tokens --- src/cc/CCinclude.h | 18 ++++-- src/cc/CCtokens.cpp | 10 ++- src/cc/CCtokens.h | 1 - src/cc/CCtx.cpp | 31 +++++---- src/cc/CCutils.cpp | 47 +++++++++++++- src/cc/gateways.cpp | 153 ++++++++++++++++++++++++++++---------------- src/cc/heir.cpp | 2 +- 7 files changed, 182 insertions(+), 80 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 1b6e804fc..3e70ba380 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -91,10 +91,14 @@ struct CCcontract_info char unspendableCCaddr[64], CChexstr[72], normaladdr[64]; uint8_t CCpriv[32]; - // this for 1of2 key spending condition (for this evalcode) + // this for 1of2 keys coins cryptocondition (for this evalcode) // NOTE: only one evalcode is allowed at this time - char unspendable1of2addr[64]; - CPubKey unspendable1of2pk[2]; + char coins1of2addr[64]; + CPubKey coins1of2pk[2]; + + // the same for tokens 1of2 keys cc + char tokens1of2addr[64]; + CPubKey tokens1of2pk[2]; // this is for spending from two additional 'unspendable' CC addresses of other eval codes // (that is, for spending from several cc contract 'unspendable' addresses): @@ -153,15 +157,15 @@ uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk); int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); - bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); + +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra); -//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid,uint256 &assetid2,int64_t &price,std::vector &origpubkey); uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector &data); int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen); @@ -182,6 +186,10 @@ CC* GetCryptoCondition(CScript const& scriptSig); void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr); void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr); + +CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2); +CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2); + bool IsCCInput(CScript const& scriptSig); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 4a2c6031e..62fb1fa78 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -51,7 +51,7 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector origpubkey,st } // this is for other contracts which use tokens and build customized extra payloads to token's opret: -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys) +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) { CScript opret; uint8_t ccType = 0; @@ -63,10 +63,14 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); - opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; if (ccType >= 1) ss << voutPubkeys[0]; if (ccType == 2) ss << voutPubkeys[1];); + opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ + if(ccType >= 1) ss << voutPubkeys[0]; \ + if(ccType == 2) ss << voutPubkeys[1]; \ + if(payload.size() > 0) ss << payload); return(opret); } + uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description) { std::vector vopret; uint8_t dummyEvalcode, funcid, *script; @@ -578,7 +582,7 @@ std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector d std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(pubkey2pk(destpubkey)); // dest pubkey for validating vout - return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet('t', EVAL_TOKENS, assetid, voutTokenPubkeys))); // By setting EVAL_TOKENS we're getting out from assets validation code + return(FinalizeCCTx(mask, cp, mtx, mypk, txfee, EncodeTokenOpRet('t', EVAL_TOKENS, assetid, voutTokenPubkeys, CScript()))); // By setting EVAL_TOKENS we're getting out from assets validation code } else { fprintf(stderr, "not enough CC token inputs for %.8f\n", (double)total / COIN); diff --git a/src/cc/CCtokens.h b/src/cc/CCtokens.h index f65a56b41..34223bc0b 100644 --- a/src/cc/CCtokens.h +++ b/src/cc/CCtokens.h @@ -31,7 +31,6 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t //int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description); std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys); //this is in CCinclude.h int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 79473b87a..ec0a24b3f 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -45,7 +45,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; - CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *cond; + CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond; CPubKey unspendablepk; n = mtx.vout.size(); @@ -130,7 +130,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran else { Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey); - //fprintf(stderr,"vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); + //fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); if ( strcmp(destaddr,myaddr) == 0 ) { privkey = myprivkey; @@ -140,37 +140,44 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = unspendablepriv; cond = othercond; - //fprintf(stderr,"unspendable CC addr.(%s)\n",unspendable); + //fprintf(stderr,"FinalizeCCTx() unspendable CC addr.(%s)\n",unspendable); } // check if this is the 2nd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr2) == 0) { - //fprintf(stderr,"matched %s unspendable2!\n",cp->unspendableaddr2); + //fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2); privkey = cp->unspendablepriv2; - if ( othercond2 == 0 ) //&& cp->evalcode != EVAL_CHANNELS && cp->evalcode != EVAL_HEIR && cp->evalcode != EVAL_ASSETS && cp->evalcode != EVAL_TOKENS) + if ( othercond2 == 0 ) othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2); - //else if ( othercond2 == 0 && (cp->evalcode == EVAL_CHANNELS || cp->evalcode == EVAL_HEIR || cp->evalcode == EVAL_ASSETS || cp->evalcode == EVAL_TOKENS) ) - // othercond2 = MakeCCcond1of2(cp->evalcode2,cp->unspendablepk2,cp->unspendablepk3); cond = othercond2; } // check if this is 3rd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 ) { - //fprintf(stderr,"matched %s unspendable3!\n",cp->unspendableaddr3); + //fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3); privkey = cp->unspendablepriv3; if ( othercond3 == 0 ) othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3); cond = othercond3; } - // check if this is spending from 1of2 cc addr: - else if (strcmp(cp->unspendable1of2addr, destaddr) == 0) + // check if this is spending from 1of2 cc coins addr: + else if (strcmp(cp->coins1of2addr, destaddr) == 0) { - //fprintf(stderr,"matched %s unspendable1of2!\n",cp->unspendable1of2addr); + fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr); privkey = myprivkey; if (othercond1of2 == 0) - othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->unspendable1of2pk[0], cp->unspendable1of2pk[1]); + othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]); cond = othercond1of2; } + // check if this is spending from 1of2 cc tokens addr: + else if (strcmp(cp->tokens1of2addr, destaddr) == 0) + { + fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr); + privkey = myprivkey; + if (othercond1of2tokens == 0) + othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->tokens1of2pk[0], cp->tokens1of2pk[1]); + cond = othercond1of2tokens; + } else { fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index eef21c72a..c07755c2a 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -76,6 +76,39 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2) return(vout); } +CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) +{ + // make 1of2 sigs cond + std::vector pks; + pks.push_back(CCNewSecp256k1(pk1)); + pks.push_back(CCNewSecp256k1(pk2)); + CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); // this is eval cc + CC *cond1of2Sig = CCNewThreshold(1, pks); // this is 1 of 2 sigs cc + CC *cond1of2Threshold = CCNewThreshold(2, { condEvalCC, cond1of2Sig }); + + // make token cond + struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); + + std::vector pksTokens; + pks.push_back(CCNewSecp256k1(unspendableTokensPk)); + CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // this is eval cc + CC *condUnspendableSig = CCNewThreshold(1, pksTokens); // this is 1 of 2 sigs cc + CC *condTopThreshold = CCNewThreshold(2, { condEvalTokensCC, condUnspendableSig }); + + return CCNewThreshold(2, { cond1of2Threshold, condTopThreshold }); +} + +CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) +{ + CTxOut vout; + CC *payoutCond = MakeTokensCCcond1of2(evalcode, pk1, pk2); + vout = CTxOut(nValue, CCPubKey(payoutCond)); + cc_free(payoutCond); + return(vout); +} + CC* GetCryptoCondition(CScript const& scriptSig) { auto pc = scriptSig.begin(); @@ -198,9 +231,17 @@ void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t * // set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 cryptocondition vout: void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr) { - cp->unspendable1of2pk[0] = pk1; - cp->unspendable1of2pk[1] = pk2; - strcpy(cp->unspendable1of2addr, coinaddr); + cp->coins1of2pk[0] = pk1; + cp->coins1of2pk[1] = pk2; + strcpy(cp->coins1of2addr, coinaddr); +} + +// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 tokens cryptocondition vout: +void CCaddr1of2setTokens(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr) +{ + cp->tokens1of2pk[0] = pk1; + cp->tokens1of2pk[1] = pk2; + strcpy(cp->tokens1of2addr, coinaddr); } bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index 2768e9fbd..c64d56b80 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -132,14 +132,18 @@ Implementation Issues: - When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly. + -- When thinking about validation, it is clear that we cant use EVAL_ASSETS for the locked coins as there wont be any enforcement of the gateways locking. + -- This means we need a way to transfer assets into gateways outputs and back. It seems a tokenconvert rpc will be needed and hopefully that will be enough to make it all work properly. + ++ The use of tokenconvert has been changed to the use of the new Tokens contract which can enforce other contracts validation by forwarding eval->validate call to GatewaysValidate + ++ So all tokens remain within that Tokens contract eval code. - Care must be taken so that tokens are not lost and can be converted back. - - This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241 - - The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS. + -- Care must be taken so that tokens are not lost and can be converted back. + -- This changes the usage to require tokenconvert before doing the bind and also tokenconvert before doing a withdraw. EVAL_GATEWAYS has evalcode of 241 + ++ tokenconvert now returns 'not implemented', no need to use it at all. + -- The gatewaysclaim automatically converts the deposit amount of tokens back to EVAL_ASSETS. + ++ The gatewaysclaim automatically transfers the deposit amount of tokens to depositor's address (within EVAL_TOKENS). + */ @@ -204,38 +208,42 @@ uint8_t DecodeGatewaysDepositOpRet(const CScript &scriptPubKey,std::string &coin return(0); } -CScript EncodeGatewaysClaimOpRet(uint8_t funcid,uint256 assetid,std::string refcoin,uint256 bindtxid,uint256 deposittxid,CPubKey destpub,int64_t amount) +// encodes payload for the token opret (needs to be added to the tail of it) +CScript EncodeGatewaysClaimOpRet(uint8_t funcid, std::string refcoin, uint256 bindtxid, uint256 deposittxid, CPubKey destpub, int64_t amount) { - CScript opret; uint8_t evalcode = EVAL_ASSETS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << bindtxid << deposittxid << destpub << amount); + CScript opret; + + opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << bindtxid << deposittxid << destpub << amount); return(opret); } -uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &assetid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) +uint8_t DecodeGatewaysClaimOpRet(const CScript &scriptPubKey,uint256 &tokenid,std::string &refcoin,uint256 &bindtxid,uint256 &deposittxid,CPubKey &destpub,int64_t &amount) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> bindtxid; ss >> deposittxid; ss >> destpub; ss >> amount) != 0 ) { return(f); } return(0); } -CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid,uint256 assetid, std::string refcoin, CPubKey withdrawpub, int64_t amount) +CScript EncodeGatewaysWithdrawOpRet(uint8_t funcid, std::string refcoin, CPubKey withdrawpub, int64_t amount) { - CScript opret; uint8_t evalcode = EVAL_GATEWAYS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << assetid << refcoin << withdrawpub << amount); + CScript opret; + opret << OP_RETURN << E_MARSHAL(ss << funcid << refcoin << withdrawpub << amount); return(opret); } -uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &assetid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) +uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &tokenid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) { std::vector vopret; uint8_t *script,e,f; + + GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> assetid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> tokenid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) { return(f); } @@ -304,7 +312,7 @@ uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey) std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_ASSETS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 ) + if ( vopret.size() > 2 && (script[0] == EVAL_GATEWAYS || script[0] == EVAL_TOKENS) && E_UNMARSHAL(vopret,ss >> e; ss >> f) != 0 ) { if (f == 'B' && f == 'D' && f == 't' && f == 'W' && f == 'P' && f == 'M') return(f); @@ -512,7 +520,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks,height,claimvout; bool retval; uint8_t funcid,hash[32],M,N,taddr,prefix,prefix2; char str[65],destaddr[64],depositaddr[65],validationError[512]; std::vector txids; std::vector pubkeys,publishers,tmppublishers; std::vector proof; int64_t totalsupply,amount,tmpamount; - uint256 hashblock,txid,bindtxid,deposittxid,assetid,oracletxid,tokenid,cointxid,tmptxid,tmpxtxid2,merkleroot,mhash; CTransaction bindtx,deposittx,oracletx; + uint256 hashblock,txid,bindtxid,deposittxid,tokenidClaim,oracletxid,tokenidBind,cointxid,tmptxid,tmpxtxid2,merkleroot,mhash; CTransaction bindtx,deposittx,oracletx; std::string refcoin,tmprefcoin,deposithex; CPubKey destpub,tmpdestpub; fprintf(stderr,"return true without gateways validation\n"); @@ -565,8 +573,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & //vin.2: CC input of marker from gatewaysdeposit tx //vout.0: CC vout of total tokens from deposit amount to asset eval code //(vout.1): CC vout if there is change of unused tokens back to owner of tokens (deposit amount less than available tokens) - //vout.n-1: opreturn - 't' assetid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code) - if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,refcoin,bindtxid,deposittxid,destpub,amount)==0) + //vout.n-1: opreturn - 't' tokenid zeroid 0 mypubkey (NOTE: opreturn is with asset eval code) + if ((numvouts=tx.vout.size()) > 0 && DecodeGatewaysClaimOpRet(tx.vout[numvouts-1].scriptPubKey,tokenidClaim,refcoin,bindtxid,deposittxid,destpub,amount)==0) return eval->Invalid("invalid gatewaysclaim OP_RETURN data!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for gatewaysClaim!"); @@ -580,12 +588,12 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("vout.1 is CC for gatewaysClaim!"); else if (myGetTransaction(bindtxid,bindtx,hashblock) == 0) return eval->Invalid("invalid gatewaysbind txid!"); - else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') + else if ((numvouts=bindtx.vout.size()) > 0 && DecodeGatewaysBindOpRet(depositaddr,bindtx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenidBind,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 'B') return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); else if (tmprefcoin!=refcoin) return eval->Invalid("refcoin different in bind tx"); - else if (tokenid!=assetid) - return eval->Invalid("assetid does not match tokenid from gatewaysbind"); + else if (tokenidClaim!=tokenidBind) + return eval->Invalid("tokenid does not match tokenid from gatewaysbind"); else if (komodo_txnotarizedconfirmed(bindtxid) == false) return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); else if (myGetTransaction(deposittxid,deposittx,hashblock) == 0) @@ -642,7 +650,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & //vout.1: normal vout txfee marker to withdraw destination pubkey //vout.2: CC vout txfee marker to gateways CC address //vout.n-2: CC vout if there is change of unused tokens back to owner of tokens (withdraw amount less than owner available tokens) - //vout.n-1: opreturn - 'W' assetid refcoin withdrawpub amount + //vout.n-1: opreturn - 'W' tokenid refcoin withdrawpub amount break; case 'P': //vin.0: normal input @@ -675,9 +683,9 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & // helper functions for rpc calls in rpcwallet.cpp -int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 refassetid,int64_t total,int32_t maxinputs) +int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 reftokenid,int64_t total,int32_t maxinputs) { - char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; + char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 tokenid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); @@ -701,11 +709,11 @@ int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP if ( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 ) continue; GetOpReturnData(vintx.vout[vintx.vout.size()-1].scriptPubKey, vopret); - if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> assetid) != 0 ) + if ( E_UNMARSHAL(vopret,ss >> evalcode; ss >> funcid; ss >> tokenid) != 0 ) { - assetid = revuint256(assetid); - char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for refassetid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,refassetid),uint256_str(str2,assetid),(double)vintx.vout[vout].nValue/COIN); - if ( assetid == refassetid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) + tokenid = revuint256(tokenid); + char str[65],str2[65]; fprintf(stderr,"vout.%d %d:%d (%c) check for reftokenid.%s vs %s %.8f\n",vout,evalcode,cp->evalcode,funcid,uint256_str(str,reftokenid),uint256_str(str2,tokenid),(double)vintx.vout[vout].nValue/COIN); + if ( tokenid == reftokenid && funcid == 't' && (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) { //fprintf(stderr,"total %llu maxinputs.%d %.8f\n",(long long)total,maxinputs,(double)it->second.satoshis/COIN); if ( total != 0 && maxinputs != 0 ) @@ -905,7 +913,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui CTransaction tx; CPubKey mypk,gatewayspk,tmpdestpub; struct CCcontract_info *cp,C; uint8_t M,N,taddr,prefix,prefix2; std::string coin, deposithex; std::vector msigpubkeys,publishers; int64_t totalsupply,depositamount,tmpamount,inputs,CCchange=0; int32_t numvouts,claimvout,height; std::vector proof; - uint256 hashBlock,assetid,oracletxid,tmptxid,cointxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; std::vector txids; + uint256 hashBlock,tokenid,oracletxid,tmptxid,cointxid; char str[65],depositaddr[64],coinaddr[64],destaddr[64]; std::vector txids; cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) @@ -917,7 +925,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) { fprintf(stderr,"invalid coin - bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); @@ -945,17 +953,24 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui //fprintf(stderr,"depositaddr.(%s) vs %s\n",depositaddr,cp->unspendableaddr2); if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) { - if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,assetid,amount,60)) > 0 ) + ///////// if ( (inputs= AddGatewaysInputs(cp,mtx,gatewayspk,tokenid,amount,60)) > 0 ) + if ((inputs = AddTokenCCInputs(cp, mtx, gatewayspk, tokenid, amount, 60)) > 0) { if ( inputs > amount ) CCchange = (inputs - amount); _GetCCaddress(destaddr,EVAL_GATEWAYS,mypk); //printf("expecting deposittxid/v0 to be to %s\n",destaddr); mtx.vin.push_back(CTxIn(deposittxid,0,CScript())); // triggers EVAL_GATEWAYS validation - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,amount,mypk)); // transfer back to normal token + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,amount,mypk)); // transfer back to normal token if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysClaimOpRet('t',assetid,refcoin,bindtxid,deposittxid,destpub,amount))); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,gatewayspk)); + + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(mypk); // the pubkey where tokens are going (vout[0]) + + return(FinalizeCCTx(0,cp,mtx,mypk,txfee, + EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys, + EncodeGatewaysClaimOpRet('t', refcoin, bindtxid, deposittxid, destpub, amount)))); // yes, 't' is passed twice } } CCerror = strprintf("cant find enough inputs or mismatched total"); @@ -966,39 +981,67 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; - uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; + CTransaction tx; + CPubKey mypk, gatewayspk; + uint256 tokenid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; - cp = CCinit(&C,EVAL_GATEWAYS); + struct CCcontract_info *cpGateways, gatewaysC; + struct CCcontract_info *cpTokens, tokensC; + + cpGateways = CCinit(&gatewaysC, EVAL_GATEWAYS); + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + if ( txfee == 0 ) txfee = 10000; + mypk = pubkey2pk(Mypubkey()); - gatewayspk = GetUnspendable(cp,0); - if ( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) + gatewayspk = GetUnspendable(cpGateways, 0); + + if( GetTransaction(bindtxid,tx,hashBlock,false) == 0 || (numvouts= tx.vout.size()) <= 0 ) { fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(""); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) + if( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || coin != refcoin ) { fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),coin.c_str()); return(""); } - if ( AddNormalinputs(mtx,mypk,3*txfee,4) > 0 ) + if( AddNormalinputs(mtx, mypk, 3*txfee, 4) > 0 ) { - if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,assetid,amount,60)) > 0 ) + /////if ( (inputs= AddGatewaysInputs(cp,mtx,mypk,tokenid,amount,60)) > 0 ) + if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, amount, 60)) > 0) { if ( inputs > amount ) CCchange = (inputs - amount); - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,amount,gatewayspk)); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, gatewayspk)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG)); - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS, txfee, gatewayspk)); if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeGatewaysWithdrawOpRet('W',assetid,refcoin,withdrawpub,amount))); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); + + char unspendableGatewaysAddr[64]; + GetCCaddress(cpGateways, unspendableGatewaysAddr, gatewayspk); + + uint8_t unspendableGatewaysPrivkey[32]; + GetUnspendable(cpGateways, unspendableGatewaysPrivkey); + + // add additional unspendable addr from Gateways: + CCaddr2set(cpTokens, EVAL_GATEWAYS, gatewayspk, unspendableGatewaysPrivkey, unspendableGatewaysAddr); + + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(gatewayspk); // the pubkey where tokens are going vout[0] (and for checking the 'change' the Tokens contract will find pubkeys itself) + + return(FinalizeCCTx(0, cpTokens, mtx, mypk, txfee, + EncodeTokenOpRet('t', EVAL_GATEWAYS, tokenid, voutTokenPubkeys, + EncodeGatewaysWithdrawOpRet('W', refcoin, withdrawpub, amount)))); } + CCerror = strprintf("cant find enough token inputs or mismatched total"); + fprintf(stderr, "%s\n", CCerror.c_str()); + return(""); + } - CCerror = strprintf("cant find enough inputs or mismatched total"); + CCerror = strprintf("cant find enough normal inputs or mismatched total"); fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } @@ -1073,7 +1116,7 @@ std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string ref UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) { UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; - uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + uint256 hashBlock,tokenid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; char depositaddr[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],cctxidaddr[64],signeraddr[64]; int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; std::vector > unspentOutputs; @@ -1087,7 +1130,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(result); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) { fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); return(result); @@ -1108,7 +1151,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) nValue = (int64_t)it->second.satoshis; fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && - DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) + DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) { Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); @@ -1141,7 +1184,7 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) { UniValue result(UniValue::VOBJ),processed(UniValue::VARR); CTransaction tx; std::string tmprefcoin,hex; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; - uint256 withdrawtxid,hashBlock,txid,assetid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + uint256 withdrawtxid,hashBlock,txid,tokenid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; char depositaddr[64],coinaddr[64],str[65],numstr[32],txidaddr[64],cctxidaddr[64],withaddr[64]; int32_t i,n,numvouts,vout,queueflag; int64_t totalsupply,nValue,amount; struct CCcontract_info *cp,C; std::vector > unspentOutputs; @@ -1155,7 +1198,7 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) fprintf(stderr,"cant find bindtxid %s\n",uint256_str(str,bindtxid)); return(result); } - if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,assetid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) + if ( DecodeGatewaysBindOpRet(depositaddr,tx.vout[numvouts-1].scriptPubKey,tmprefcoin,tokenid,totalsupply,oracletxid,M,N,msigpubkeys,taddr,prefix,prefix2) != 'B' || tmprefcoin != refcoin ) { fprintf(stderr,"invalid bindtxid %s coin.%s\n",uint256_str(str,bindtxid),tmprefcoin.c_str()); return(result); @@ -1178,7 +1221,7 @@ UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin) if ( vout == 0 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysCompleteSigningOpRet(tx.vout[numvouts-1].scriptPubKey,tmprefcoin,withdrawtxid,hex) == 'C' && myIsutxo_spentinmempool(txid,vout) == 0) { - if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W') + if (GetTransaction(withdrawtxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size())>0 && DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmprefcoin,withdrawpub,amount) == 'W') { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid",uint256_str(str,txid))); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 7d5ea7cfe..fe93e7a5a 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -690,7 +690,7 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, if ((inputs=Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners //mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,amount,HeirCCpk)); - mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk + mtx.vout.push_back(MakeTokensCC1of2vout(/*Helper::getMyEval()*/EVAL_HEIR, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk // add a marker for finding all plans in HeirList() CPubKey HeirContractPubKey = GetUnspendable(cp, 0); From 53b30074c22beab4b229884ef558844122ec32ef Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 14:00:29 +0500 Subject: [PATCH 013/106] corrected vpayload serialisation to opret --- src/cc/CCtokens.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 62fb1fa78..8e4dc17ca 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -62,11 +62,14 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t tokenid = revuint256(tokenid); //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; + std::vector vpayload; + GetOpReturnData(payload, vpayload); + //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ if(ccType >= 1) ss << voutPubkeys[0]; \ if(ccType == 2) ss << voutPubkeys[1]; \ - if(payload.size() > 0) ss << payload); + if(payload.size() > 0) ss << vpayload); return(opret); } From 00968fd9cbc3353523ed909df5615014bb99760e Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 14:45:39 +0500 Subject: [PATCH 014/106] destaddr logging added --- src/cc/CCtx.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index ec0a24b3f..30c4c1e62 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -131,6 +131,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey); //fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); + std::cerr << "FinalizeCCtx() destaddr=" << destaddr << " myaddr=" << myaddr << std::endl; if ( strcmp(destaddr,myaddr) == 0 ) { privkey = myprivkey; From c2942d60a487571a6d9c6a1d0a52d72e48fe84b4 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 15:23:07 +0500 Subject: [PATCH 015/106] Tokens CC cond test code added to HeirClaim TokenValidate --- src/cc/CCinclude.h | 2 ++ src/cc/CCtokens.cpp | 2 +- src/cc/CCutils.cpp | 14 +++++++++++++- src/cc/heir.cpp | 6 +++--- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 3e70ba380..2ebba82f7 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -189,6 +189,8 @@ void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *c CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2); CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2); +bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2); +void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr); bool IsCCInput(CScript const& scriptSig); int32_t unstringbits(char *buf,uint64_t bits); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 8e4dc17ca..362529a53 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -337,7 +337,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c if (voutPubkeys.size() == 1) testVout = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]); else // voutPubkeys.size() == 2 - testVout = MakeCC1of2vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]); + testVout = MakeTokensCC1of2vout(EVAL_TOKENS, 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; diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index c07755c2a..f677127a6 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -237,7 +237,7 @@ void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *c } // set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 tokens cryptocondition vout: -void CCaddr1of2setTokens(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr) +void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr) { cp->tokens1of2pk[0] = pk1; cp->tokens1of2pk[1] = pk2; @@ -348,6 +348,18 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK return(destaddr[0] != 0); } +bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2) +{ + CC *payoutCond; + destaddr[0] = 0; + if ((payoutCond = MakeTokensCCcond1of2(cp->evalcode, pk, pk2)) != 0) + { + Getscriptaddress(destaddr, CCPubKey(payoutCond)); + cc_free(payoutCond); + } + return(destaddr[0] != 0); +} + bool ConstrainVout(CTxOut vout, int32_t CCflag, char *cmpaddr, int64_t nValue) { char destaddr[64]; diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index fe93e7a5a..1d776a865 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -578,7 +578,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, std::vector> unspentOutputs; char coinaddr[64]; - GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 pubkey of 2 pubkeys' + GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 pubkey of 2 pubkeys' SetCCunspents(unspentOutputs, coinaddr); // char markeraddr[64]; @@ -930,7 +930,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee uint8_t myprivkey[32]; char coinaddr[64]; // set priv key addresses in CC structure: - GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); Myprivkey(myprivkey); ////fprintf(stderr,"HeirClaim() before setting unspendable CC addr2= (%s) addr3= (%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); @@ -938,7 +938,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee //CCaddr3set(cp, Helper::getMyEval(), heirPubkey, myprivkey, coinaddr); ////fprintf(stderr, "HeirClaim() after setting unspendable CC addr2=(%s) addr3=(%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); - CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); // add 1of2 vout validation pubkeys: std::vector voutTokenPubkeys; From aa7c48f529c5154fbc6ecaba1cda140fb100e005 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 15:35:09 +0500 Subject: [PATCH 016/106] corrected EVAL_HEIR (test) in IsTokenVout --- src/cc/CCtokens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 362529a53..644e9d414 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -337,7 +337,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c if (voutPubkeys.size() == 1) testVout = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]); else // voutPubkeys.size() == 2 - testVout = MakeTokensCC1of2vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]); + testVout = MakeTokensCC1of2vout(EVAL_HEIR, 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; From 732144ebb8078179fc8888d21591dfe63ab8729c Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 15:50:55 +0500 Subject: [PATCH 017/106] turn off HeirValidate temp --- src/cc/heir.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 1d776a865..fcea30f58 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -160,6 +160,9 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction std::cerr << "HeirValidate funcid=" << (char)funcId << std::endl; + //////////////// temp //////////////////////// + return true; + switch (funcId) { case 'F': // fund coins: From 37105d851ab083ab430674e16db64f0f8220c616 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 16:06:00 +0500 Subject: [PATCH 018/106] added logging in Add1of2addrinputs in heir --- src/cc/heir.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index fcea30f58..30143a2cf 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -587,7 +587,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, // char markeraddr[64]; // CCtxidaddr(markeraddr, fundingtxid); // SetCCunspents(unspentOutputs, markeraddr); - // std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << std::endl; + std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << std::endl; for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { uint256 txid = it->first.txhash; @@ -595,6 +595,9 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, int32_t voutIndex = (int32_t)it->first.index; // no need to prevent dup // dimxy: maybe it is good to put tx's in cache? + + std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl; + if (GetTransaction(txid, heirtx, hashBlock, false) != 0) { uint256 tokenid; uint256 fundingTxidInOpret; @@ -608,7 +611,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, (voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && !myIsutxo_spentinmempool(txid, voutIndex)) { - //std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; + std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; if (total != 0 && maxinputs != 0) mtx.vin.push_back(CTxIn(txid, voutIndex, CScript())); nValue = it->second.satoshis; From 092b4c987ab6c8deebd5a6af41ad2d001a777d66 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 16:12:09 +0500 Subject: [PATCH 019/106] eval_heir corrected temp in HeirClaim --- src/cc/heir.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 30143a2cf..22268279b 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -864,7 +864,8 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee uint8_t hasHeirSpendingBegun = 0; - cp = CCinit(&C, Helper::getMyEval()); + //cp = CCinit(&C, Helper::getMyEval()); + cp = CCinit(&C, EVAL_HEIR); if (txfee == 0) txfee = 10000; From 0177628e7dca790f24da6f3692e067dd96a62d5b Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 16:19:48 +0500 Subject: [PATCH 020/106] GetTokensCCaddress1of2 call corrected (test) in IsHeirFundingVout --- src/cc/heir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 22268279b..57d7c6a79 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -252,7 +252,7 @@ int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, in { char destaddr[65], heirFundingAddr[65]; - GetCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey); + GetTokensCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey); if (tx.vout[voutIndex].scriptPubKey.IsPayToCryptoCondition() != 0) { // NOTE: dimxy it was unsafe 'Getscriptaddress(destaddr,tx.vout[voutIndex].scriptPubKey) > 0' here: if (Getscriptaddress(destaddr, tx.vout[voutIndex].scriptPubKey) && strcmp(destaddr, heirFundingAddr) == 0) From d67ca1779af0e5446cab6ca978d126b4f793e1c5 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 21:28:13 +0500 Subject: [PATCH 021/106] MakeTokensCCcond1of2 corrrected and simplified --- src/cc/CCtokens.cpp | 2 +- src/cc/CCutils.cpp | 16 +++------------- src/cc/heir.cpp | 2 +- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 644e9d414..0829623e6 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -173,7 +173,7 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & if ((funcid = DecodeTokenOpRet(tx.vout[numvouts - 1].scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, vopretExtra)) == 0) return eval->Invalid("TokenValidate: invalid opreturn payload"); - fprintf(stderr, "TokensValidate (%c)\n", funcid); + fprintf(stderr, "TokensValidate (%c) evalcode=0x%0x\n", funcid, cp->evalcode); if (eval->GetTxUnconfirmed(tokenid, createTx, hashBlock) == 0) return eval->Invalid("cant find token create txid"); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index f677127a6..93c82945e 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -83,21 +83,11 @@ CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) pks.push_back(CCNewSecp256k1(pk1)); pks.push_back(CCNewSecp256k1(pk2)); CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); // this is eval cc + CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // this is eval token cc CC *cond1of2Sig = CCNewThreshold(1, pks); // this is 1 of 2 sigs cc - CC *cond1of2Threshold = CCNewThreshold(2, { condEvalCC, cond1of2Sig }); + CC *cond1of2Threshold = CCNewThreshold(3, { condEvalCC, condEvalTokensCC, cond1of2Sig }); - // make token cond - struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); - - std::vector pksTokens; - pks.push_back(CCNewSecp256k1(unspendableTokensPk)); - CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // this is eval cc - CC *condUnspendableSig = CCNewThreshold(1, pksTokens); // this is 1 of 2 sigs cc - CC *condTopThreshold = CCNewThreshold(2, { condEvalTokensCC, condUnspendableSig }); - - return CCNewThreshold(2, { cond1of2Threshold, condTopThreshold }); + return cond1of2Threshold; } CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 57d7c6a79..9bb3f7f93 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -158,7 +158,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction fundingTxOpRetScript = tx.vout[numvouts - 1].scriptPubKey; } - std::cerr << "HeirValidate funcid=" << (char)funcId << std::endl; + std::cerr << "HeirValidate funcid=" << (char)funcId << " evalcode=" << cpHeir->evalcode << std::endl; //////////////// temp //////////////////////// return true; From 805b3da0501341585d06c83fc94d1011023462fe Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 10 Jan 2019 21:42:10 +0500 Subject: [PATCH 022/106] heir evalcode logging added --- src/cc/heir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 9bb3f7f93..73d8b49aa 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -158,7 +158,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction fundingTxOpRetScript = tx.vout[numvouts - 1].scriptPubKey; } - std::cerr << "HeirValidate funcid=" << (char)funcId << " evalcode=" << cpHeir->evalcode << std::endl; + std::cerr << "HeirValidate funcid=" << (char)funcId << " evalcode=" << (int)cpHeir->evalcode << std::endl; //////////////// temp //////////////////////// return true; From 6d509d52931a155992c06711ac93f25350314a4a Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 11 Jan 2019 14:34:56 +0500 Subject: [PATCH 023/106] added MakeTokensCCcond1 and MakeTokensCCvout1 --- src/cc/CCinclude.h | 2 + src/cc/CCtokens.cpp | 102 +++++++++++++++++++++++++------------------- src/cc/CCutils.cpp | 19 +++++++++ src/cc/heir.cpp | 2 +- 4 files changed, 81 insertions(+), 44 deletions(-) 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': From c4c58b484ab83355debb181addf8cb04571f0a30 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 11 Jan 2019 23:02:37 +0500 Subject: [PATCH 024/106] heir modified for two eval Tokens changed to new 2-opret format --- src/cc/CCinclude.h | 2 + src/cc/CCtokens.cpp | 43 ++++--- src/cc/CCtx.cpp | 22 +++- src/cc/CCutils.cpp | 25 ++++- src/cc/heir.cpp | 250 +++++++++++++++++++++++++---------------- src/cc/heir_validate.h | 159 +++++++++++++++++++------- 6 files changed, 342 insertions(+), 159 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 0dc7f446d..4b6b437b4 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -191,6 +191,8 @@ CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubK 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 GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, 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 2f9a50a93..0bd4dd991 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -201,10 +201,10 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & //vout.0: issuance tokenoshis to CC //vout.1: normal output for change (if any) //vout.n-1: opreturn EVAL_TOKENS 'c' - if (evalCodeInOpret != EVAL_TOKENS) - return eval->Invalid("unexpected TokenValidate for createtoken"); - else - return true; + //if (evalCodeInOpret != EVAL_TOKENS) + // return eval->Invalid("unexpected TokenValidate for createtoken"); + //else + return true; case 't': // transfer //vin.0: normal input @@ -225,15 +225,15 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & // forward validation if evalcode in opret is not EVAL_TOKENS // init for forwarding validation call - if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS? - struct CCcontract_info *cpOther = NULL, C; + //if (evalCodeInOpret != EVAL_TOKENS) { // TODO: should we check also only allowed for tokens evalcodes, like EVAL_ASSETS, EVAL_GATEWAYS? + // struct CCcontract_info *cpOther = NULL, C; - cpOther = CCinit(&C, evalCodeInOpret); - if (cpOther) - return cpOther->validate(cpOther, eval, tx, nIn); - else - return eval->Invalid("unsupported evalcode in opret"); - } + // cpOther = CCinit(&C, evalCodeInOpret); + // if (cpOther) + // return cpOther->validate(cpOther, eval, tx, nIn); + // else + // return eval->Invalid("unsupported evalcode in opret"); + //} return true; // what does this do? // return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); @@ -285,17 +285,18 @@ bool ExtractVinPubkeys(struct CCcontract_info *cp, CTransaction tx, std::vector< thread_local uint32_t tokenValIndentSize = 0; // validates opret for token tx: -bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, uint8_t &evalCodeInOpret, std::vector &voutPubkeys, std::vector &vopretExtra) { +bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector &voutPubkeys, std::vector &vopretExtra) { uint256 tokenidOpret, tokenidOpret2; uint8_t funcid; + uint8_t dummyEvalCode; // 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, evalCodeInOpret, tokenidOpret, voutPubkeys, vopretExtra)) == 0) + if ((funcid = DecodeTokenOpRet(tx.vout[n - 1].scriptPubKey, dummyEvalCode, tokenidOpret, voutPubkeys, vopretExtra)) == 0) { std::cerr << indentStr << "ValidateTokenOpret() DecodeTokenOpret could not parse opret for txid=" << tx.GetHash().GetHex() << std::endl; return(false); @@ -364,14 +365,24 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; - uint8_t evalCodeInOpret = 0; - const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, evalCodeInOpret, voutPubkeys, vopretExtra); + const bool valOpret = ValidateTokenOpret(tx, v, reftokenid, 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: + CScript contractScript = CScript(vopretExtra); + std::vector vcontractOpret; + + GetOpReturnData(contractScript, vcontractOpret); + if (vcontractOpret.size() == 0) { + std::cerr << "IsTokensvout() empty contract opret" << std::endl; + return 0; + } + + uint8_t evalCodeInOpret = vcontractOpret.begin()[0]; + if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { CTxOut testVout; if (voutPubkeys.size() == 1) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 30c4c1e62..d85f59473 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -43,9 +43,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; - int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; + int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64],mytokensaddr[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; - CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond; + CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL; CPubKey unspendablepk; n = mtx.vout.size(); @@ -61,11 +61,17 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran return("0"); } Myprivkey(myprivkey); - unspendablepk = GetUnspendable(cp,unspendablepriv); + GetCCaddress(cp,myaddr,mypk); mycond = MakeCCcond1(cp->evalcode,mypk); + + GetTokensCCaddress(cp, myaddr, mypk); + mytokenscond = MakeTokensCCcond1(cp->evalcode, mypk); + + unspendablepk = GetUnspendable(cp,unspendablepriv); GetCCaddress(cp,unspendable,unspendablepk); - othercond = MakeCCcond1(cp->evalcode,unspendablepk); + othercond = MakeCCcond1(cp->evalcode,unspendablepk); + //Reorder vins so that for multiple normal vins all other except vin0 goes to the end //This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation. for (i=0; icoins1of2addr, destaddr) == 0) + else if (strcmp(cp->coins1of2addr, destaddr) == 0) { fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr); privkey = myprivkey; diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 82b74cc11..6d2d4a037 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -94,8 +94,8 @@ 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 *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); // add eval cc + CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // add also eval token cc CC *Sig = CCNewThreshold(1, pks); return CCNewThreshold(3, { condEvalCC, condEvalTokensCC, Sig }); } @@ -345,6 +345,27 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk) return(_GetCCaddress(destaddr,cp->evalcode,pk)); } +bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, CPubKey pk) +{ + CC *payoutCond; + destaddr[0] = 0; + if ((payoutCond = MakeTokensCCcond1(evalcode, pk)) != 0) + { + Getscriptaddress(destaddr, CCPubKey(payoutCond)); + cc_free(payoutCond); + } + return(destaddr[0] != 0); +} + +bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk) +{ + destaddr[0] = 0; + if (pk.size() == 0) + pk = GetUnspendable(cp, 0); + return(_GetTokensCCaddress(destaddr, cp->evalcode, pk)); +} + + bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubKey pk2) { CC *payoutCond; diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 7d1d56006..784e0a88c 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -122,23 +122,27 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction //if (chainActive.Height() < 741) // return true; - uint8_t funcId; uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenid = zeroid; CScript fundingTxOpRetScript; uint8_t hasHeirSpendingBegun = 0, dummyHasHeirSpendingBegun; - int32_t heirType = NOT_HEIR; - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); - if(funcId != 0) - heirType = HEIR_COINS; - else { - funcId = DecodeHeirOpRet(tx.vout[numvouts - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, false); - if (funcId != 0) - heirType = HEIR_TOKENS; + + uint8_t evalCodeTokens = 0; + std::vector voutPubkeys; + std::vector vopretExtra; + + CScript heirScript = tx.vout[tx.vout.size() - 1].scriptPubKey; + int32_t heirType = HEIR_COINS; + + uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); + if (funcId != 0) { + heirScript = CScript(vopretExtra); + heirType = HEIR_TOKENS; } + funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); - if (heirType == NOT_HEIR) + if (funcId == 0) return eval->Invalid("invalid opreturn format"); if (funcId != 'F') { @@ -248,11 +252,11 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction * Checks if vout is to cryptocondition address * @return vout value in satoshis */ -int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, int32_t voutIndex, CPubKey ownerPubkey, CPubKey heirPubkey) +template int64_t IsHeirFundingVout(struct CCcontract_info* cp, const CTransaction& tx, int32_t voutIndex, CPubKey ownerPubkey, CPubKey heirPubkey) { char destaddr[65], heirFundingAddr[65]; - GetTokensCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey); + Helper::GetCoinsOrTokensCCaddress1of2(cp, heirFundingAddr, ownerPubkey, heirPubkey); if (tx.vout[voutIndex].scriptPubKey.IsPayToCryptoCondition() != 0) { // NOTE: dimxy it was unsafe 'Getscriptaddress(destaddr,tx.vout[voutIndex].scriptPubKey) > 0' here: if (Getscriptaddress(destaddr, tx.vout[voutIndex].scriptPubKey) && strcmp(destaddr, heirFundingAddr) == 0) @@ -317,6 +321,8 @@ CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpe fundingtxid = revuint256(fundingtxid); return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun); } + +/* // makes opret for tokens while they are inside Heir contract address space - initial funding CScript EncodeHeirTokensCreateOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) { @@ -348,10 +354,11 @@ CScript EncodeHeirTokensOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun) { +/*uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun) { uint8_t heirFuncId = 0; hasHeirSpendingBegun = 0; @@ -363,70 +370,66 @@ uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, } \ }); - if (!result /*|| assetFuncId != 't' -- any tx is ok*/) + if (!result )// || assetFuncId != 't' -- any tx is ok) return (uint8_t)0; return heirFuncId; -} +}*/ + /** * decode opret vout for Heir contract */ -template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) +uint8_t _DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { - - std::vector vopretExtra; + std::vector vopret; uint8_t evalCodeInOpret = 0; - uint256 dummyTokenid; - std::vector voutPubkeysDummy; + uint8_t heirFuncId = 0; fundingTxidInOpret = zeroid; //to init - tokenid = zeroid; - - if (typeid(Helper) == typeid(TokenHelper)) { // if caller thinks it is a token - - // First - decode token opret: - uint8_t tokenFuncId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra); - if (tokenFuncId == 0) { - if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: not heir token opret, tokenFuncId=" << (int)tokenFuncId << std::endl; - return (uint8_t)0; - } + GetOpReturnData(scriptPubKey, vopret); + if (vopret.size() == 0) { + if (!noLogging) std::cerr << "_DecodeHeirOpRet() warning: empty opret" << std::endl; + return (uint8_t)0; } - else { - std::vector vopret; - - GetOpReturnData(scriptPubKey, vopret); - if (vopret.size() == 0) { - if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl; - return (uint8_t)0; - } - evalCodeInOpret = vopret.begin()[0]; - vopretExtra = std::vector( vopret.begin()+1, vopret.end() ); // vopretExtra = vopret + 1, get it for futher parsing - } - - if (vopretExtra.size() > 1 && evalCodeInOpret == EVAL_HEIR) { + evalCodeInOpret = vopret.begin()[0]; + + if (vopret.size() > 1 && evalCodeInOpret == EVAL_HEIR) { // NOTE: it unmarshals for all F, A and C - uint8_t heirFuncId = _UnmarshalOpret(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun); - - /*std::cerr << "DecodeHeirOpRet()" + uint8_t heirFuncId = 0; + hasHeirSpendingBegun = 0; + + bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; \ + if (heirFuncId == 'F') { \ + ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; \ + } \ + else { \ + ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \ + } \ + }); + + if (!result) { + if (!noLogging) std::cerr << "_DecodeHeirOpRet() could not unmarshal opret, evalCode=" << (int)evalCodeInOpret << std::endl; + return (uint8_t)0; + } + + /* std::cerr << "DecodeHeirOpRet()" << " heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << " ownerPubkey=" << HexStr(ownerPubkey) << " heirPubkey=" << HexStr(heirPubkey) << " heirName=" << heirName << " inactivityTime=" << inactivityTime - << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << std::endl;*/ + << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << std::endl; */ - - //if (e == EVAL_HEIR && IS_CHARINSTR(funcId, "FAC")) - if (Helper::isMyFuncId(heirFuncId)) { + if (isMyFuncId(heirFuncId)) { fundingTxidInOpret = revuint256(fundingTxidInOpret); return heirFuncId; } else { - if(!noLogging) std::cerr << "DecodeHeirOpRet() error: unexpected opret, heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << std::endl; + if(!noLogging) std::cerr << "_DecodeHeirOpRet() unexpected opret type, heirFuncId=" << (char)(heirFuncId ? heirFuncId : ' ') << std::endl; } } else { - if (!noLogging) std::cerr << "DecodeHeirOpRet() error: not a heir opret, vopretExtra.size() == 0 or not EVAL_HEIR evalcode=" << (int)evalCodeInOpret << std::endl; + if (!noLogging) std::cerr << "_DecodeHeirOpRet() not a heir opret, vopretExtra.size() == 0 or not EVAL_HEIR evalcode=" << (int)evalCodeInOpret << std::endl; } return (uint8_t)0; } @@ -434,24 +437,24 @@ template uint8_t _DecodeHeirOpRet(CScript scriptPubKey, uint256 & /** * overload for 'F' opret */ -template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) +uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { uint256 dummytxid; uint8_t dummyHasHeirSpendingBegun; - return _DecodeHeirOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging); + return _DecodeHeirOpRet(scriptPubKey, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging); } /** * overload for A, C oprets and AddHeirContractInputs */ -template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) +uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { CPubKey dummyOwnerPubkey, dummyHeirPubkey; int64_t dummyInactivityTime; std::string dummyHeirName; - return _DecodeHeirOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); + return _DecodeHeirOpRet(scriptPubKey, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); } @@ -476,9 +479,22 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ // get initial funding tx and set it as initial lasttx: if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { uint256 dummytxid; + uint8_t evalCodeTokens = 0; + std::vector vopretExtra; + std::vector dummyVoutPubkeys; - // set ownerPubkey and heirPubkey: - if ((funcId = DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) != 0) { + CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; + if (typeid(Helper) == typeid(TokenHelper)) { + if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { + heirScript = CScript(vopretExtra); + } + else { + std::cerr << "FindLatestFundingTx() could not decode token opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n'; + return zeroid; + } + } + funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName); + if (funcId != 0) { // found at least funding tx! //std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n'; fundingOpretScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; @@ -493,7 +509,7 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ std::vector> unspentOutputs; struct CCcontract_info *cp, C; - cp = CCinit(&C, Helper::getMyEval()); + cp = CCinit(&C, EVAL_HEIR); char coinaddr[64]; GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' @@ -531,9 +547,23 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ uint8_t tmpFuncId; uint8_t tmphasHeirSpendingBegun; - if (regtx.vout.size() > 0 && - (tmpFuncId = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, dummyTokenid, fundingTxidInOpret, tmphasHeirSpendingBegun, true)) != 0 && - fundingtxid == fundingTxidInOpret) { + uint8_t evalCodeTokens = 0; + std::vector vopretExtra; + std::vector dummyVoutPubkeys; + + CScript heirScript = regtx.vout[regtx.vout.size() - 1].scriptPubKey; + if (typeid(Helper) == typeid(TokenHelper)) { + if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { + heirScript = CScript(vopretExtra); + } + else { + std::cerr << "FindLatestFundingTx() could not decode token opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n'; + return zeroid; + } + } + tmpFuncId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, tmphasHeirSpendingBegun, true); + + if (regtx.vout.size() > 0 && tmpFuncId != 0 && fundingtxid == fundingTxidInOpret) { if (blockHeight > maxBlockHeight) { maxBlockHeight = blockHeight; @@ -581,12 +611,13 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, std::vector> unspentOutputs; char coinaddr[64]; - GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 pubkey of 2 pubkeys' + Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 of 2 pubkeys' SetCCunspents(unspentOutputs, coinaddr); // char markeraddr[64]; // CCtxidaddr(markeraddr, fundingtxid); // SetCCunspents(unspentOutputs, markeraddr); + std::cerr << "Add1of2AddressInputs() using 1of2addr=" << coinaddr << " unspentOutputs.size()=" << unspentOutputs.size() << std::endl; for (std::vector>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { @@ -602,13 +633,22 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, uint256 tokenid; uint256 fundingTxidInOpret; uint8_t dummyHasHeirSpendingBegun; + uint8_t evalCodeTokens = 0; + std::vector vopretExtra; + std::vector voutPubkeys; - uint8_t funcId = DecodeHeirOpRet(heirtx.vout[heirtx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); + CScript heirScript = heirtx.vout[heirtx.vout.size() - 1].scriptPubKey; + uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); + if (funcId != 0) { + heirScript = CScript(vopretExtra); + } + funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); + if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && funcId != 0 && - Helper::isMyFuncId(funcId) && + isMyFuncId(funcId) && // (typeid(Helper) == typeid(TokenHelper) && IsHeirvout(true, cp, nullptr, tokenid, vintx, voutIndex) > 0) && // deep validation for tokens - not used anymore - (voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && + (voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && !myIsutxo_spentinmempool(txid, voutIndex)) { std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; @@ -631,7 +671,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, template int64_t LifetimeHeirContractFunds(struct CCcontract_info* cp, uint256 fundingtxid, CPubKey ownerPubkey, CPubKey heirPubkey) { char coinaddr[64]; - GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' + Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' std::vector> addressIndexes; SetCCtxids(addressIndexes, coinaddr); @@ -644,17 +684,24 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info CTransaction tx; if (GetTransaction(txid, tx, hashBlock, false) && tx.vout.size() > 0) { - uint8_t funcId; + uint8_t evalCodeTokens = 0; uint256 tokenid; uint256 fundingTxidInOpret; - const int32_t ivout = 0; + std::vector vopretExtra; + std::vector voutPubkeys; uint8_t dummyHasHeirSpendingBegun; - - funcId = DecodeHeirOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, tokenid, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); + const int32_t ivout = 0; + + CScript heirScript = tx.vout[tx.vout.size() - 1].scriptPubKey; + uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); + if (funcId != 0) { + heirScript = CScript(vopretExtra); + } + funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); //std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n'; - if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && Helper::isMyFuncId(funcId) && !Helper::isSpendingTx(funcId) + if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && isMyFuncId(funcId) && !isSpendingTx(funcId) /* && !myIsutxo_spentinmempool(txid, ccVoutIdx) */) // include also tx in mempool { total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change) @@ -678,7 +725,7 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); struct CCcontract_info *cp, C; - cp = CCinit(&C, Helper::getMyEval()); + cp = CCinit(&C, EVAL_HEIR); if (txfee == 0) txfee = 10000; @@ -719,7 +766,6 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, // add change for txfee and opreturn vouts and sign tx: return (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - // CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'F' << myPubkey << heirPubkey << inactivityTimeSec << heirName))); Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName))); } else // TODO: need result return unification with heiradd and claim @@ -759,7 +805,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in uint8_t funcId; uint8_t hasHeirSpendingBegun = 0; - cp = CCinit(&C, Helper::getMyEval()); + cp = CCinit(&C, EVAL_HEIR); if (txfee == 0) txfee = 10000; @@ -790,7 +836,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */ // add cryptocondition to spend this funded amount for either pk - mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), amount, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! + mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! if (inputs > amount) change = (inputs - amount); // -txfee <-- txfee pays user @@ -801,7 +847,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); } - // add 1of2 vout validation pubkeys: + // add 1of2 vout validation pubkeys - needed only for tokens: std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(ownerPubkey); voutTokenPubkeys.push_back(heirPubkey); @@ -863,8 +909,6 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee std::string heirName; uint8_t hasHeirSpendingBegun = 0; - - //cp = CCinit(&C, Helper::getMyEval()); cp = CCinit(&C, EVAL_HEIR); if (txfee == 0) txfee = 10000; @@ -924,7 +968,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee // change to 1of2 funding addr: if (change != 0) { // vout[1] - mtx.vout.push_back(MakeCC1of2vout(Helper::getMyEval(), change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! + mtx.vout.push_back(Helper::make1of2Vout(change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! } // add marker vout: @@ -937,7 +981,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee uint8_t myprivkey[32]; char coinaddr[64]; // set priv key addresses in CC structure: - GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); Myprivkey(myprivkey); ////fprintf(stderr,"HeirClaim() before setting unspendable CC addr2= (%s) addr3= (%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); @@ -945,9 +989,9 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee //CCaddr3set(cp, Helper::getMyEval(), heirPubkey, myprivkey, coinaddr); ////fprintf(stderr, "HeirClaim() after setting unspendable CC addr2=(%s) addr3=(%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); - CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); - // add 1of2 vout validation pubkeys: + // add 1of2 vout validation pubkeys (this is for tokens): std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(ownerPubkey); voutTokenPubkeys.push_back(heirPubkey); @@ -1017,15 +1061,22 @@ UniValue HeirInfo(uint256 fundingtxid) // get initial funding tx and set it as initial lasttx: if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { - int32_t heirType = NOT_HEIR; const bool noLogging = true; + uint8_t evalCodeTokens = 0; + std::vector voutPubkeys; + std::vector vopretExtra; - if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging) == 'F') - heirType = HEIR_COINS; - else if (DecodeHeirOpRet(fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging) == 'F') + CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; + int32_t heirType = HEIR_COINS; + + uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); + if (funcId != 0) { + heirScript = CScript(vopretExtra); heirType = HEIR_TOKENS; - else - { + } + funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); + + if( funcId == 0 ) { std::cerr << "HeirInfo() initial tx F not found for this fundingtx" << std::endl; result.push_back(Pair("result", "error")); result.push_back(Pair("error", "initial tx F not found")); @@ -1033,10 +1084,7 @@ UniValue HeirInfo(uint256 fundingtxid) } struct CCcontract_info *cp, C; - if (heirType == HEIR_COINS) - cp = CCinit(&C, CoinHelper::getMyEval()); - else - cp = CCinit(&C, TokenHelper::getMyEval()); + cp = CCinit(&C, EVAL_HEIR); uint8_t hasHeirSpendingBegun = 0; @@ -1174,14 +1222,24 @@ template void _HeirList(struct CCcontract_info *cp, UniValue &r //std::cerr << "HeirList() checking txid=" << txid.GetHex() << " vout=" << vout << '\n'; - CTransaction inittx; - if (GetTransaction(txid, inittx, hashBlock, false) != 0 && (inittx.vout.size() - 1) > 0) { + CTransaction fundingtx; + if (GetTransaction(txid, fundingtx, hashBlock, false) != 0 && (fundingtx.vout.size() - 1) > 0) { CPubKey ownerPubkey, heirPubkey; std::string heirName; int64_t inactivityTimeSec; const bool noLogging = true; - uint8_t funcId = DecodeHeirOpRet(inittx.vout[inittx.vout.size() - 1].scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); + uint8_t evalCodeTokens = 0; + uint256 tokenid; + std::vector vopretExtra; + std::vector voutPubkeys; + + CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; + uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); + if (funcId != 0) { + heirScript = CScript(vopretExtra); + } + funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); // note: if it is not Heir token funcId would be equal to 0 if (funcId == 'F') { diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 5b5df2110..0094f5f4c 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -14,19 +14,21 @@ CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); // makes token opret -CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName); -CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan); +//CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName); +//CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan); template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan); -template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false); -template uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false); +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); + +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 bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); } - static uint8_t getMyEval() { return EVAL_HEIR; } static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { return AddNormalinputs(mtx, ownerPubkey, total, maxinputs); } @@ -40,43 +42,58 @@ public: static CScript makeClaimOpRet(uint256 dummyid, std::vector dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { return EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan); } - - static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } - + 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(struct CCcontract_info* cp, char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) { + return GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + } + static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info* cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { + CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + } }; // helper class to allow polymorphic behaviour for HeirXXX() functions in case of tokens class TokenHelper { public: - static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); } - static uint8_t getMyEval() { return EVAL_TOKENS; } static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { return AddTokenCCInputs(cp, mtx, ownerPubkey, tokenid, total, maxinputs); } static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { - return EncodeHeirTokensCreateOpRet((uint8_t)'F', tokenid, voutTokenPubkeys, ownerPubkey, heirPubkey, inactivityTimeSec, heirName); + return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys, + EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName)); } static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeHeirTokensOpRet((uint8_t)'A', tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan); + return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys, + EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan)); } static CScript makeClaimOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeHeirTokensOpRet((uint8_t)'C', tokenid, voutTokenPubkeys, fundingtxid, isHeirSpendingBegan); + return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys, + EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan)); } - static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } - + 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); + return MakeTokensCC1vout(EVAL_HEIR, amount, myPubkey); } static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) { - return MakeCC1vout(EVAL_TOKENS, amount, myPubkey); + return MakeTokensCC1vout(EVAL_HEIR, amount, myPubkey); + } + static bool GetCoinsOrTokensCCaddress1of2(struct CCcontract_info* cp, char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) { + return GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + } + + static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info* cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { + CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); } }; @@ -307,11 +324,8 @@ public: 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; } @@ -350,14 +364,12 @@ private: 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) {} @@ -390,13 +402,28 @@ public: virtual bool validateVout(CTxOut vout, std::string& message) const { //std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl; - uint8_t funcId; CPubKey ownerPubkey, heirPubkey; int64_t inactivityTime; std::string heirName; uint256 tokenid; + + uint8_t evalCodeTokens = 0; + std::vector vopretExtra; + std::vector dummyVoutPubkeys; - if ((funcId = DecodeHeirOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) == 0) { + CScript heirScript = m_fundingOpretScript; + if (typeid(Helper) == typeid(TokenHelper)) { + if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { + heirScript = CScript(vopretExtra); + } + else { + message = m_customMessage + std::string(" invalid token opreturn format"); + std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; + return false; + } + } + uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false); + if (funcId == 0) { message = m_customMessage + std::string(" invalid opreturn format"); std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; return false; @@ -443,21 +470,35 @@ public: { //std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl; - uint8_t funcId; CPubKey ownerPubkey, heirPubkey; int64_t inactivityTime; std::string heirName; uint256 tokenid; ///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl; + + uint8_t evalCodeTokens = 0; + std::vector vopretExtra; + std::vector dummyVoutPubkeys; + + CScript ownerScript; + CScript heirScript = m_fundingOpretScript; + if (typeid(Helper) == typeid(TokenHelper)) { + if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { + heirScript = CScript(vopretExtra); + } + else { + message = std::string("invalid token opreturn format"); + return false; + } + } // get both pubkeys: - if ((funcId = DecodeHeirOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName)) == 0) { + uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false); + if (funcId == 0) { message = std::string("invalid opreturn format"); return false; } - CScript ownerScript; - CScript heirScript; if (m_checkNormals) { ownerScript = CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey; heirScript = CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey; @@ -474,7 +515,6 @@ public: // 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; @@ -503,15 +543,28 @@ public: { //std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl; - uint8_t funcId; CPubKey ownerPubkey, heirPubkey; int64_t inactivityTime; std::string heirName; uint256 tokenid; + uint8_t evalCodeTokens = 0; + std::vector vopretExtra; + std::vector dummyVoutPubkeys; + + CScript heirScript = m_fundingOpretScript; + if (typeid(Helper) == typeid(TokenHelper)) { + if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { + heirScript = CScript(vopretExtra); + } else { + message = std::string("invalid token opreturn format"); + return false; + } + } // get heir pubkey: - if ((funcId = DecodeHeirOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, false)) == 0) { + uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false); + if (funcId == 0) { message = std::string("invalid opreturn format"); return false; } @@ -560,28 +613,54 @@ public: { //std::cerr << "COpRetValidator::validateVout() entered" << std::endl; - uint8_t funcId, initialFuncId; // do not check heir name - uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid, initialTokenid; + uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid; uint8_t dummyIsHeirSpendingBegan; - if ((funcId = DecodeHeirOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan)) == 0) { + uint8_t evalCodeTokens = 0; + std::vector vopretExtra; + std::vector dummyVoutPubkeys; + + CScript heirScript = vout.scriptPubKey; + if (typeid(Helper) == typeid(TokenHelper)) { + if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { + heirScript = CScript(vopretExtra); + } else { + message = std::string("invalid token opreturn format"); + return false; + } + } + uint8_t funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyIsHeirSpendingBegan); + if (funcId == 0) { message = std::string("invalid opreturn format"); return false; } - if ((initialFuncId = DecodeHeirOpRet(m_fundingOpretScript, initialTokenid, dummyTxid, dummyIsHeirSpendingBegan)) == 0) { + + heirScript = m_fundingOpretScript; + if (typeid(Helper) == typeid(TokenHelper)) { + if (DecodeTokenOpRet(heirScript, evalCodeTokens, initialTokenid, dummyVoutPubkeys, vopretExtra) != 0) { + heirScript = CScript(vopretExtra); + } else { + message = std::string("invalid initial token opreturn format"); + return false; + } + } + uint8_t initialFuncId = DecodeHeirOpRet(heirScript, dummyTxid, dummyIsHeirSpendingBegan); + if (initialFuncId == 0) { message = std::string("invalid initial tx opreturn format"); return false; } // validation rules: - if (!Helper::isMyFuncId(funcId)) { + if (!isMyFuncId(funcId)) { message = std::string("invalid funcid in opret"); return false; } - if(tokenid != initialTokenid ) { - message = std::string("invalid tokenid 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; From 6065a6dec46de16b29b271932e1b482cc56eef76 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 01:06:24 +0500 Subject: [PATCH 025/106] corrected -> no token vout pubkey validation for 'c' modified MakeTokenCCcond1 and 1of2 to eliminate duplicate evals --- src/cc/CCtokens.cpp | 22 +++++++++++----------- src/cc/CCutils.cpp | 24 +++++++++++++++--------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 0bd4dd991..5c848b081 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -285,7 +285,7 @@ bool ExtractVinPubkeys(struct CCcontract_info *cp, CTransaction tx, std::vector< 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) { +uint8_t ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector &voutPubkeys, std::vector &vopretExtra) { uint256 tokenidOpret, tokenidOpret2; uint8_t funcid; @@ -305,7 +305,7 @@ bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector { if (tokenid != zeroid && tokenid == tx.GetHash() && v == 0) { //std::cerr << indentStr << "ValidateTokenOpret() this is the tokenbase 'c' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl; - return(true); + return funcid; } } else if (funcid == 't') @@ -313,18 +313,18 @@ bool ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vector //std::cerr << indentStr << "ValidateTokenOpret() tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; if (tokenid != zeroid && tokenid == tokenidOpret) { //std::cerr << indentStr << "ValidateTokenOpret() this is a transfer 't' tx, txid=" << tx.GetHash().GetHex() << " vout=" << v << " returning true" << std::endl; - return(true); + return funcid; } } //std::cerr << indentStr << "ValidateTokenOpret() return false funcid=" << (char)funcid << " tokenid=" << tokenid.GetHex() << " tokenIdOpret=" << tokenidOpret.GetHex() << " txid=" << tx.GetHash().GetHex() << std::endl; - return false; + return (uint8_t)0; } - - // Checks if the vout is a really Tokens CC vout -// compareTotals == true, the func also validates the passed transaction itself: +// also checks tokenid in opret or txid if this is 'c' tx +// goDeeper is true: the func also validates amounts of the passed transaction: // it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx +// checkPubkeys is true: validates if the vout is token vout1 or token vout1of2. Should always be true! int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &vopretExtra, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys) { @@ -365,12 +365,12 @@ 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); + const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; - if (valOpret) { + if (funcId != 0) { //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 && funcId != 'c') { // verify that the vout is token's (for 'c' there is no pubkeys!): CScript contractScript = CScript(vopretExtra); std::vector vcontractOpret; @@ -605,7 +605,7 @@ std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector d if (inputs > total) CCchange = (inputs - total); //for (i=0; i pks; pks.push_back(CCNewSecp256k1(pk1)); pks.push_back(CCNewSecp256k1(pk2)); - CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); // this is eval cc - CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // this is eval token cc - CC *cond1of2Sig = CCNewThreshold(1, pks); // this is 1 of 2 sigs cc - CC *cond1of2Threshold = CCNewThreshold(3, { condEvalCC, condEvalTokensCC, cond1of2Sig }); - return cond1of2Threshold; + std::vector thresholds; + thresholds.push_back( CCNewEval(E_MARSHAL(ss << evalcode)) ); + if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()! + thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc + thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc + + return CCNewThreshold(thresholds.size(), thresholds); } CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) { std::vector pks; pks.push_back(CCNewSecp256k1(pk)); - CC *condEvalCC = CCNewEval(E_MARSHAL(ss << evalcode)); // add eval cc - CC *condEvalTokensCC = CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS)); // add also eval token cc - CC *Sig = CCNewThreshold(1, pks); - return CCNewThreshold(3, { condEvalCC, condEvalTokensCC, Sig }); + + std::vector thresholds; + thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode))); + if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()! + thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc + thresholds.push_back(CCNewThreshold(1, pks)); // signature + + return CCNewThreshold(thresholds.size(), thresholds); } CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) From 0a76f9d8972b3a33eac9c0600c093982b85420f1 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 15:20:55 +0500 Subject: [PATCH 026/106] AssetXXX() changed to GetTokenBalance, TokenInfo, TokenList added processing of incorrect tokenid to GetTokenBalance --- src/cc/CCassets.h | 6 ++-- src/cc/CCassetstx.cpp | 57 --------------------------------- src/cc/CCtokens.cpp | 68 ++++++++++++++++++++++++++++++++++++++++ src/cc/CCtokens.h | 4 +++ src/wallet/rpcwallet.cpp | 29 ++++++++++++----- 5 files changed, 96 insertions(+), 68 deletions(-) diff --git a/src/cc/CCassets.h b/src/cc/CCassets.h index 5a5ef2c82..39644efc6 100644 --- a/src/cc/CCassets.h +++ b/src/cc/CCassets.h @@ -47,12 +47,12 @@ int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpp bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid); // CCassetstx -int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); +//int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); // --> GetTokenBalance() int64_t AddAssetInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 assetid, int64_t total, int32_t maxinputs); UniValue AssetOrders(uint256 tokenid); -UniValue AssetInfo(uint256 tokenid); -UniValue AssetList(); +//UniValue AssetInfo(uint256 tokenid); +//UniValue AssetList(); //std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description); //std::string AssetTransfer(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total); //std::string AssetConvert(int64_t txfee,uint256 assetid,std::vector destpubkey,int64_t total,int32_t evalcode); diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 1c2012534..3047876f4 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -66,63 +66,6 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK } -int64_t GetAssetBalance(CPubKey pk,uint256 tokenid) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_TOKENS); - return(AddTokenCCInputs(cp,mtx,pk,tokenid,0,0)); -} - -UniValue AssetInfo(uint256 assetid) -{ - UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; std::vector origpubkey; std::string name,description; char str[67],numstr[65]; - if ( GetTransaction(assetid,vintx,hashBlock,false) == 0 ) - { - fprintf(stderr,"cant find assetid\n"); - result.push_back(Pair("result","error")); - result.push_back(Pair("error","cant find assetid")); - return(result); - } - if ( vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) == 0 ) - { - fprintf(stderr,"assetid isnt token creation txid\n"); - result.push_back(Pair("result","error")); - result.push_back(Pair("error","assetid isnt token creation txid")); - } - result.push_back(Pair("result","success")); - result.push_back(Pair("tokenid",uint256_str(str,assetid))); - result.push_back(Pair("owner",pubkey33_str(str,origpubkey.data()))); - result.push_back(Pair("name",name)); - result.push_back(Pair("supply",vintx.vout[0].nValue)); - result.push_back(Pair("description",description)); - return(result); -} - -UniValue AssetList() -{ - UniValue result(UniValue::VARR); - std::vector > addressIndex; - struct CCcontract_info *cp,C; uint256 txid,hashBlock; - CTransaction vintx; std::vector origpubkey; - std::string name,description; char str[65]; - - cp = CCinit(&C,EVAL_TOKENS); - SetCCtxids(addressIndex,cp->normaladdr); - for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) - { - txid = it->first.txhash; - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) - { - if ( vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,origpubkey,name,description) != 0 ) - { - result.push_back(uint256_str(str,txid)); - } - } - } - return(result); -} - UniValue AssetOrders(uint256 refassetid) { static uint256 zero; diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 5c848b081..613d4452f 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -623,4 +623,72 @@ std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector d fprintf(stderr, "not enough normal inputs for txfee\n"); } return(""); +} + + +int64_t GetTokenBalance(CPubKey pk, uint256 tokenid) +{ + uint256 hashBlock; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction tokentx; + + if (GetTransaction(tokenid, tokentx, hashBlock, false) == 0) + { + fprintf(stderr, "cant find tokenid\n"); + CCerror = strprintf("cant find tokenid"); + return 0; + } + + struct CCcontract_info *cp, C; + cp = CCinit(&C, EVAL_TOKENS); + return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0)); +} + +UniValue TokenInfo(uint256 tokenid) +{ + UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; std::vector origpubkey; std::string name, description; char str[67], numstr[65]; + if (GetTransaction(tokenid, vintx, hashBlock, false) == 0) + { + fprintf(stderr, "cant find assetid\n"); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "cant find tokenid")); + return(result); + } + if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description) == 0) + { + fprintf(stderr, "assetid isnt token creation txid\n"); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "assetid isnt token creation txid")); + } + result.push_back(Pair("result", "success")); + result.push_back(Pair("tokenid", uint256_str(str, tokenid))); + result.push_back(Pair("owner", pubkey33_str(str, origpubkey.data()))); + result.push_back(Pair("name", name)); + result.push_back(Pair("supply", vintx.vout[0].nValue)); + result.push_back(Pair("description", description)); + return(result); +} + +UniValue TokenList() +{ + UniValue result(UniValue::VARR); + std::vector > addressIndex; + struct CCcontract_info *cp, C; uint256 txid, hashBlock; + CTransaction vintx; std::vector origpubkey; + std::string name, description; char str[65]; + + cp = CCinit(&C, EVAL_TOKENS); + SetCCtxids(addressIndex, cp->normaladdr); + for (std::vector >::const_iterator it = addressIndex.begin(); it != addressIndex.end(); it++) + { + txid = it->first.txhash; + if (GetTransaction(txid, vintx, hashBlock, false) != 0) + { + if (vintx.vout.size() > 0 && DecodeTokenCreateOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, origpubkey, name, description) != 0) + { + result.push_back(uint256_str(str, txid)); + } + } + } + return(result); } \ No newline at end of file diff --git a/src/cc/CCtokens.h b/src/cc/CCtokens.h index 34223bc0b..e7bb62101 100644 --- a/src/cc/CCtokens.h +++ b/src/cc/CCtokens.h @@ -32,6 +32,10 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description); std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); +int64_t GetTokenBalance(CPubKey pk, uint256 tokenid); +UniValue TokenInfo(uint256 tokenid); +UniValue TokenList(); + //this is in CCinclude.h int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); //this is in CCinclude.h uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b39a19668..2cf195661 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6947,7 +6947,7 @@ UniValue tokenlist(const UniValue& params, bool fHelp) throw runtime_error("tokenlist\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - return(AssetList()); + return(TokenList()); } UniValue tokeninfo(const UniValue& params, bool fHelp) @@ -6958,7 +6958,7 @@ UniValue tokeninfo(const UniValue& params, bool fHelp) if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); tokenid = Parseuint256((char *)params[0].get_str().c_str()); - return(AssetInfo(tokenid)); + return(TokenInfo(tokenid)); } UniValue tokenorders(const UniValue& params, bool fHelp) @@ -6977,22 +6977,35 @@ UniValue tokenorders(const UniValue& params, bool fHelp) UniValue tokenbalance(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); char destaddr[64]; uint256 tokenid; uint64_t balance; std::vector pubkey; struct CCcontract_info *cp,C; + CCerror.clear(); + cp = CCinit(&C,EVAL_ASSETS); if ( fHelp || params.size() > 2 ) throw runtime_error("tokenbalance tokenid [pubkey]\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - LOCK(cs_main); + + LOCK(cs_main); + tokenid = Parseuint256((char *)params[0].get_str().c_str()); if ( params.size() == 2 ) pubkey = ParseHex(params[1].get_str().c_str()); - else pubkey = Mypubkey(); + else + pubkey = Mypubkey(); result.push_back(Pair("result", "success")); - if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 ) + if (GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0) result.push_back(Pair("CCaddress",destaddr)); - balance = GetAssetBalance(pubkey2pk(pubkey),tokenid); - result.push_back(Pair("tokenid", params[0].get_str())); - result.push_back(Pair("balance", (int64_t)balance)); + + balance = GetTokenBalance(pubkey2pk(pubkey),tokenid); + + if (CCerror.empty()) { + result.push_back(Pair("tokenid", params[0].get_str())); + result.push_back(Pair("balance", (int64_t)balance)); + } + else { + ERR_RESULT(CCerror); + } + return(result); } From 15c71c69f1bb0351992a983cb0aa770ee2361f71 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 15:30:21 +0500 Subject: [PATCH 027/106] corrected GetCCaddress call in get TokenBalance --- src/wallet/rpcwallet.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2cf195661..847ddd921 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6976,7 +6976,7 @@ UniValue tokenorders(const UniValue& params, bool fHelp) UniValue tokenbalance(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); char destaddr[64]; uint256 tokenid; uint64_t balance; std::vector pubkey; struct CCcontract_info *cp,C; + UniValue result(UniValue::VOBJ); uint256 tokenid; uint64_t balance; std::vector pubkey; struct CCcontract_info *cp,C; CCerror.clear(); cp = CCinit(&C,EVAL_ASSETS); @@ -6992,13 +6992,17 @@ UniValue tokenbalance(const UniValue& params, bool fHelp) pubkey = ParseHex(params[1].get_str().c_str()); else pubkey = Mypubkey(); - result.push_back(Pair("result", "success")); - if (GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0) - result.push_back(Pair("CCaddress",destaddr)); balance = GetTokenBalance(pubkey2pk(pubkey),tokenid); if (CCerror.empty()) { + char destaddr[64]; + + result.push_back(Pair("result", "success")); + + if (GetCCaddress(cp, destaddr, pubkey2pk(pubkey)) != 0) + result.push_back(Pair("CCaddress", destaddr)); + result.push_back(Pair("tokenid", params[0].get_str())); result.push_back(Pair("balance", (int64_t)balance)); } From 0d6eb9853a4a8c2a1262cdc669ad2129e9f907d0 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 15:48:45 +0500 Subject: [PATCH 028/106] added logging to IsTokenVout --- src/cc/CCtokens.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 613d4452f..167a0a241 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -366,9 +366,9 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); - //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << funcId << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (funcId != 0) { - //std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned true" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (checkPubkeys && funcId != 'c') { // verify that the vout is token's (for 'c' there is no pubkeys!): @@ -391,7 +391,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c 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; + 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; return tx.vout[v].nValue; } } @@ -401,12 +401,13 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c 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; + 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; return tx.vout[v].nValue; } } } else { + std::cerr << indentStr << "IsTokensvout() returns without pubkey check value=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; return tx.vout[v].nValue; } } From bfce0c18b87635acdf856f4274ce90910156b56c Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 16:11:04 +0500 Subject: [PATCH 029/106] getMyEval() resurrection --- src/cc/CCtokens.cpp | 10 +++++----- src/cc/heir.cpp | 2 +- src/cc/heir_validate.h | 2 ++ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 167a0a241..939f1e7d7 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -108,7 +108,7 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 funcId = script[1]; //fprintf(stderr,"decode.[%c]\n",funcId); - switch ( funcId ) + switch( funcId ) { case 'c': return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription); @@ -366,7 +366,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); - std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << funcId << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (funcId != 0) { std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; @@ -490,7 +490,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t // add inputs from token cc addr int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs) { - char coinaddr[64], destaddr[64]; + char tokenaddr[64], destaddr[64]; int64_t threshold, nValue, price, totalinputs = 0; uint256 txid, hashBlock; std::vector vopretExtra; @@ -498,8 +498,8 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C int32_t j, vout, n = 0; std::vector > unspentOutputs; - GetCCaddress(cp, coinaddr, pk); - SetCCunspents(unspentOutputs, coinaddr); + GetTokensCCaddress(cp, tokenaddr, pk); + SetCCunspents(unspentOutputs, tokenaddr); threshold = total / (maxinputs != 0 ? maxinputs : 64); // TODO: is maxinputs really could not be over 64? what if i want to calc total balance? diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 784e0a88c..5e9eb4362 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -725,7 +725,7 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); struct CCcontract_info *cp, C; - cp = CCinit(&C, EVAL_HEIR); + cp = CCinit(&C, Helper::getMyEval()); if (txfee == 0) txfee = 10000; diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 0094f5f4c..88d1d2745 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -29,6 +29,7 @@ inline static bool isSpendingTx(uint8_t funcid) { return (funcid == 'C'); } class CoinHelper { public: + static uint8_t getMyEval() { return EVAL_HEIR; } static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { return AddNormalinputs(mtx, ownerPubkey, total, maxinputs); } @@ -62,6 +63,7 @@ public: // 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(struct CCcontract_info* cp, uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { return AddTokenCCInputs(cp, mtx, ownerPubkey, tokenid, total, maxinputs); } From 9f1c21c5b5729e3635cb221409e39da4d0a9210b Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 16:14:31 +0500 Subject: [PATCH 030/106] corr tokenaddr name --- src/cc/CCtokens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 939f1e7d7..bc28f62ad 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -518,7 +518,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C 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) + if (strcmp(destaddr, tokenaddr) != 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); From e1ddbcaf6c8b2ba00a8b824e34e534f50f3e8847 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 16:23:41 +0500 Subject: [PATCH 031/106] corr else if in FinalizeCCtx --- src/cc/CCtokens.cpp | 2 +- src/cc/CCtx.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index bc28f62ad..266035e08 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -366,7 +366,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); - std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (funcId != 0) { std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index d85f59473..29e1fe0ab 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -138,16 +138,16 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey); //fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); std::cerr << "FinalizeCCtx() destaddr=" << destaddr << " myaddr=" << myaddr << std::endl; - if ( strcmp(destaddr,myaddr) == 0 ) + if( strcmp(destaddr,myaddr) == 0 ) { privkey = myprivkey; cond = mycond; } - if (strcmp(destaddr, mytokensaddr) == 0) // if this is TokensCC1vout + else if (strcmp(destaddr, mytokensaddr) == 0) // if this is TokensCC1vout { privkey = myprivkey; cond = mytokenscond; - //fprintf(stderr,"FinalizeCCTx() matched TokensCC1vout CC addr.(%s)\n",mytokensaddr); + fprintf(stderr,"FinalizeCCTx() matched TokensCC1vout CC addr.(%s)\n",mytokensaddr); } else if ( strcmp(destaddr,unspendable) == 0 ) { From 034198730a9dc9a02d5e946824813409df97bc7b Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 16:44:49 +0500 Subject: [PATCH 032/106] changed vcontractOpret in IsTokensVout remove extra param from IsTokensVout --- src/cc/CCinclude.h | 2 +- src/cc/CCtokens.cpp | 24 ++++++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 4b6b437b4..c42a4799e 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -155,7 +155,7 @@ uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk); //int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs); int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs); -int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); +int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, /*std::vector &origpubkey,*/ const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 266035e08..aca45fb70 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -365,17 +365,17 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; - const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); + std::vector vcontractOpret; + const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vcontractOpret); std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (funcId != 0) { std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (checkPubkeys && funcId != 'c') { // verify that the vout is token's (for 'c' there is no pubkeys!): - CScript contractScript = CScript(vopretExtra); - std::vector vcontractOpret; + //CScript contractScript = CScript(vopretExtra); + //GetOpReturnData(contractScript, vcontractOpret); - GetOpReturnData(contractScript, vcontractOpret); if (vcontractOpret.size() == 0) { std::cerr << "IsTokensvout() empty contract opret" << std::endl; return 0; @@ -421,7 +421,11 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs) bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid) { - CTransaction vinTx; uint256 hashBlock, id, id2; int32_t flag; int64_t tokenoshis; std::vector tmporigpubkey; int64_t tmpprice; + CTransaction vinTx; + uint256 hashBlock; //, id, id2; + //int32_t flag; + int64_t tokenoshis; + // std::vector tmporigpubkey; int64_t tmpprice; std::vector vinPubkeys, vinPubkeysEmpty; int32_t numvins = tx.vin.size(); @@ -449,7 +453,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, true, cpTokens, eval, tmporigpubkey, vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeys); + tokenoshis = IsTokensvout(goDeeper, true, cpTokens, eval, /*tmporigpubkey,*/ vinTx, tx.vin[i].prevout.n, tokenid, vinPubkeys); tokenValIndentSize--; if (tokenoshis != 0) { @@ -464,9 +468,9 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t for (int32_t i = 0; i vopretExtra; + //std::vector vopretExtra; CTransaction vintx; int32_t j, vout, n = 0; std::vector > unspentOutputs; @@ -524,7 +528,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C 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 ((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())); From bdc2915f16d07b7e8fe28cc7f9810402078b646f Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 16:53:14 +0500 Subject: [PATCH 033/106] corrected call to IsTokensVout --- src/cc/CCassetsCore.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 67e23837f..72404878d 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -573,7 +573,9 @@ bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_ //assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, vinTx, tx.vin[i].prevout.n, assetid); std::vector vopretExtra; std::vector vinPubkeysEmpty; - assetoshis = IsTokensvout(false, false, cpTokens, NULL, vopretExtra, vinTx, tx.vin[i].prevout.n, assetid, vinPubkeysEmpty); + + // TODO: why is IsTokensVout here?? + assetoshis = IsTokensvout(false, false, cpTokens, NULL, /* vopretExtra,*/ vinTx, tx.vin[i].prevout.n, assetid, vinPubkeysEmpty); if (assetoshis != 0) { std::cerr << "AssetExactAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl; From d2119d8c45ddf893e502672327f0e255a404a035 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 17:05:47 +0500 Subject: [PATCH 034/106] corr IsTokensVout def - extra param --- src/cc/CCtokens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index aca45fb70..833797417 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -325,7 +325,7 @@ uint8_t ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vec // goDeeper is true: the func also validates amounts of the passed transaction: // it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx // checkPubkeys is true: validates if the vout is token vout1 or token vout1of2. Should always be true! -int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector &vopretExtra, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys) +int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, /*std::vector &vopretExtra,*/ const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys) { // this is just for log messages indentation fur debugging recursive calls: From 46d9219e2152beb3749dc199eb1fa4139a97dcc4 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 12 Jan 2019 23:49:24 +0500 Subject: [PATCH 035/106] added second opret logging into IsTokenVout --- src/cc/CCtokens.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 833797417..f5716d866 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -365,7 +365,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; - std::vector vcontractOpret; + std::vector vcontractOpret, vcontractOpret2; const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vcontractOpret); std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (funcId != 0) { @@ -373,15 +373,18 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c if (checkPubkeys && funcId != 'c') { // verify that the vout is token's (for 'c' there is no pubkeys!): - //CScript contractScript = CScript(vopretExtra); - //GetOpReturnData(contractScript, vcontractOpret); + CScript contractScript = CScript(vcontractOpret); + GetOpReturnData(contractScript, vcontractOpret2); - if (vcontractOpret.size() == 0) { + std::cerr << "IsTokensvout() vcontractOpret=" << HexStr( vcontractOpret ); + std::cerr << "IsTokensvout() vcontractOpret2=" << HexStr(vcontractOpret2); + + if (vcontractOpret2.size() == 0) { std::cerr << "IsTokensvout() empty contract opret" << std::endl; return 0; } - uint8_t evalCodeInOpret = vcontractOpret.begin()[0]; + uint8_t evalCodeInOpret = vcontractOpret2.begin()[0]; if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { CTxOut testVout; From d6214fc9941848f768caac673e8f2ec4983ea727 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 00:12:23 +0500 Subject: [PATCH 036/106] corr second opret building/parsing --- src/cc/CCtokens.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index f5716d866..98199687f 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -62,14 +62,16 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t tokenid = revuint256(tokenid); //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; - std::vector vpayload; - GetOpReturnData(payload, vpayload); + //std::vector vpayload; + //GetOpReturnData(payload, vpayload); //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ - if(ccType >= 1) ss << voutPubkeys[0]; \ - if(ccType == 2) ss << voutPubkeys[1]; \ - if(payload.size() > 0) ss << vpayload); + if (ccType >= 1) ss << voutPubkeys[0]; \ + if (ccType == 2) ss << voutPubkeys[1];); + + if (payload.size() > 0) + opret << payload; return(opret); } @@ -365,26 +367,26 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; - std::vector vcontractOpret, vcontractOpret2; - const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vcontractOpret); + std::vector vopretExtra, vcontractOpret; + const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (funcId != 0) { std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned not-null" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (checkPubkeys && funcId != 'c') { // verify that the vout is token's (for 'c' there is no pubkeys!): - CScript contractScript = CScript(vcontractOpret); - GetOpReturnData(contractScript, vcontractOpret2); + CScript contractScript = CScript(vopretExtra); + GetOpReturnData(contractScript, vcontractOpret); - std::cerr << "IsTokensvout() vcontractOpret=" << HexStr( vcontractOpret ); - std::cerr << "IsTokensvout() vcontractOpret2=" << HexStr(vcontractOpret2); + std::cerr << "IsTokensvout() vcontractOpret=" << HexStr(vopretExtra) << std::endl; + std::cerr << "IsTokensvout() vcontractOpret2=" << HexStr(vcontractOpret) << std::endl;; - if (vcontractOpret2.size() == 0) { + if (vcontractOpret.size() == 0) { std::cerr << "IsTokensvout() empty contract opret" << std::endl; return 0; } - uint8_t evalCodeInOpret = vcontractOpret2.begin()[0]; + uint8_t evalCodeInOpret = vcontractOpret.begin()[0]; if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { CTxOut testVout; From c78b88725f5781f43a58b616326fef131db8aa66 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 00:17:33 +0500 Subject: [PATCH 037/106] corrected opret concat --- src/cc/CCtokens.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 98199687f..2944b6649 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -71,8 +71,8 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t if (ccType == 2) ss << voutPubkeys[1];); if (payload.size() > 0) - opret << payload; - return(opret); + opret += payload; + return opret; } From fe0cc96584161585a737c2fd9799178f48e0776b Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 00:38:22 +0500 Subject: [PATCH 038/106] corr second opret building more --- src/cc/CCtokens.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 2944b6649..53f992520 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -62,16 +62,19 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t tokenid = revuint256(tokenid); //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; - //std::vector vpayload; - //GetOpReturnData(payload, vpayload); + std::vector vpayload; + GetOpReturnData(payload, vpayload); //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ if (ccType >= 1) ss << voutPubkeys[0]; \ if (ccType == 2) ss << voutPubkeys[1];); - - if (payload.size() > 0) - opret += payload; + + //add second opret: + opret << OP_RETURN << E_MARSHAL(ss << vpayload); + +// if (payload.size() > 0) +// opret += payload; return opret; } From e24039f137c6934a4da5fcdfe7b09e0268d7434c Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 00:44:57 +0500 Subject: [PATCH 039/106] corr concat opret1+opret2 --- src/cc/CCtokens.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 53f992520..20d8fbe59 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -53,7 +53,7 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector origpubkey,st // this is for other contracts which use tokens and build customized extra payloads to token's opret: CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) { - CScript opret; + CScript opret1, opret2; uint8_t ccType = 0; if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) ccType = voutPubkeys.size(); @@ -66,16 +66,16 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t GetOpReturnData(payload, vpayload); //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); - opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ + opret1 << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ if (ccType >= 1) ss << voutPubkeys[0]; \ if (ccType == 2) ss << voutPubkeys[1];); //add second opret: - opret << OP_RETURN << E_MARSHAL(ss << vpayload); + opret2 << OP_RETURN << E_MARSHAL(ss << vpayload); // if (payload.size() > 0) // opret += payload; - return opret; + return opret1 + opret2; } From 20bd5c88b72aa70fbda1f97e6ae27d40a8608d49 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 15:14:06 +0500 Subject: [PATCH 040/106] opret processing returned to the variant without OP_RETURN opcode (cause this caused validation err) --- src/cc/CCtokens.cpp | 46 ++++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 20d8fbe59..63e2124ad 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -53,29 +53,32 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector origpubkey,st // this is for other contracts which use tokens and build customized extra payloads to token's opret: CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) { - CScript opret1, opret2; + CScript opret; + + if (evalCodeInOpret != EVAL_TOKENS) { + std::cerr << "EncodeTokenOpRet() evalCode should be EVAL_TOKENS!" << std::endl; + return opret; // return empty + } + + tokenid = revuint256(tokenid); + uint8_t ccType = 0; if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) ccType = voutPubkeys.size(); - //uint8_t evalcode = EVAL_TOKENS; - tokenid = revuint256(tokenid); - //uint8_t tokenFuncId = (isTransferrable) ? (uint8_t)'t' : (uint8_t)'l'; - std::vector vpayload; GetOpReturnData(payload, vpayload); - //opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << payload); - opret1 << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ - if (ccType >= 1) ss << voutPubkeys[0]; \ - if (ccType == 2) ss << voutPubkeys[1];); + opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ + if (ccType >= 1) ss << voutPubkeys[0]; \ + if (ccType == 2) ss << voutPubkeys[1]; \ + if (vpayload.size() > 0) ss << vpayload;); - //add second opret: - opret2 << OP_RETURN << E_MARSHAL(ss << vpayload); // if (payload.size() > 0) -// opret += payload; - return opret1 + opret2; +// opret += payload; --> "error 64: scriptpubkey" + + return opret; } @@ -370,7 +373,8 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // moved opret checking to this new reusable func (dimxy): std::vector voutPubkeys; - std::vector vopretExtra, vcontractOpret; + std::vector vopretExtra; + //std::vector vcontractOpret; const uint8_t funcId = ValidateTokenOpret(tx, v, reftokenid, voutPubkeys, vopretExtra); std::cerr << indentStr << "IsTokensvout() ValidateTokenOpret returned=" << (char)(funcId?funcId:' ') << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; if (funcId != 0) { @@ -378,18 +382,18 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c if (checkPubkeys && funcId != 'c') { // verify that the vout is token's (for 'c' there is no pubkeys!): - CScript contractScript = CScript(vopretExtra); - GetOpReturnData(contractScript, vcontractOpret); + //CScript contractScript = CScript(vopretExtra); + //GetOpReturnData(contractScript, vcontractOpret); - std::cerr << "IsTokensvout() vcontractOpret=" << HexStr(vopretExtra) << std::endl; - std::cerr << "IsTokensvout() vcontractOpret2=" << HexStr(vcontractOpret) << std::endl;; + std::cerr << "IsTokensvout() vopretExtra=" << HexStr(vopretExtra) << std::endl; + //std::cerr << "IsTokensvout() vcontractOpret=" << HexStr(vcontractOpret) << std::endl;; - if (vcontractOpret.size() == 0) { - std::cerr << "IsTokensvout() empty contract opret" << std::endl; + if (vopretExtra.size() < 2 /*|| vopretExtra.size() != vopretExtra.begin()[0]*/) { + std::cerr << "IsTokensvout() empty or incorrect contract opret" << std::endl; return 0; } - uint8_t evalCodeInOpret = vcontractOpret.begin()[0]; + uint8_t evalCodeInOpret = vopretExtra.begin()[1]; if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { CTxOut testVout; From 9edec18b96bb00667daafa0958e307e47c7e41f2 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 15:38:05 +0500 Subject: [PATCH 041/106] heirinfo logging enabled --- src/cc/heir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 5e9eb4362..7ae5d0241 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -1061,7 +1061,7 @@ UniValue HeirInfo(uint256 fundingtxid) // get initial funding tx and set it as initial lasttx: if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { - const bool noLogging = true; + const bool noLogging = false; uint8_t evalCodeTokens = 0; std::vector voutPubkeys; std::vector vopretExtra; From 32469f37c1c40cb854248361cd474ea88a9c7269 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 16:47:28 +0500 Subject: [PATCH 042/106] Added DecodeHeirEitherOpret handy func corr serialization second opret via payload --- src/cc/CCtokens.cpp | 8 +-- src/cc/heir.cpp | 145 +++++++++++++++++------------------------ src/cc/heir_validate.h | 2 + 3 files changed, 65 insertions(+), 90 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 63e2124ad..553f61163 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -71,14 +71,14 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ if (ccType >= 1) ss << voutPubkeys[0]; \ - if (ccType == 2) ss << voutPubkeys[1]; \ - if (vpayload.size() > 0) ss << vpayload;); + if (ccType == 2) ss << voutPubkeys[1];); // \ + //if (vpayload.size() > 0) ss << vpayload;); // if (payload.size() > 0) // opret += payload; --> "error 64: scriptpubkey" - - return opret; + // TODO: check or serialization to vpayload! + return opret + payload; } diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 7ae5d0241..4276fee16 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -322,60 +322,6 @@ CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpe return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun); } -/* -// makes opret for tokens while they are inside Heir contract address space - initial funding -CScript EncodeHeirTokensCreateOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName) -{ - uint8_t evalcode = EVAL_HEIR; - uint8_t ccType = 0; - if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) - ccType = voutPubkeys.size(); - - tokenid = revuint256(tokenid); - return CScript() << OP_RETURN << - E_MARSHAL(ss << evalcode << (uint8_t)'t' << tokenid << ccType; \ - if (ccType >= 1) ss << voutPubkeys[0]; \ - if (ccType == 2) ss << voutPubkeys[1]; \ - ss << heirFuncId << ownerPubkey << heirPubkey << inactivityTimeSec << hearName); -} -// makes opret for tokens while they are inside Heir contract address space - additional funding -CScript EncodeHeirTokensOpRet(uint8_t heirFuncId, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t hasHeirSpendingBegun) -{ - uint8_t evalcode = EVAL_HEIR; - uint8_t ccType = 0; - if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) - ccType = voutPubkeys.size(); - - tokenid = revuint256(tokenid); // for visualization in debug logs - fundingtxid = revuint256(fundingtxid); - return CScript() << OP_RETURN << - E_MARSHAL(ss << evalcode << (uint8_t)'t' << tokenid << ccType; \ - if (ccType >= 1) ss << voutPubkeys[0]; \ - if (ccType == 2) ss << voutPubkeys[1]; \ - ss << heirFuncId << fundingtxid << hasHeirSpendingBegun); -} -*/ - -// helper for decode heir opret payload -// NOTE: Heir for coins has the same opret as Heir for tokens -/*uint8_t _UnmarshalOpret(std::vector vopretExtra, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun) { - uint8_t heirFuncId = 0; - hasHeirSpendingBegun = 0; - - bool result = E_UNMARSHAL(vopretExtra, { ss >> heirFuncId; \ - if( heirFuncId == 'F') { \ - ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; \ - } else { \ - ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \ - } \ - }); - - if (!result )// || assetFuncId != 't' -- any tx is ok) - return (uint8_t)0; - - return heirFuncId; -}*/ - /** * decode opret vout for Heir contract */ @@ -457,7 +403,47 @@ uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8 return _DecodeHeirOpRet(scriptPubKey, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); } +// decode combined opret: +uint8_t _DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) +{ + uint8_t evalCodeTokens = 0; + std::vector voutPubkeys; + std::vector vopretExtra; + CScript heirScript = scriptPubKey; + int32_t heirType = HEIR_COINS; + + if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra) != 0) { + if (vopretExtra.size() > 1) { + // restore the second opret: + heirScript = CScript(); + std::vector vopretStripped = std::vector(vopretExtra.begin()+1, vopretExtra.end()); //strip string size + heirScript << OP_RETURN << E_MARSHAL(ss << vopretStripped); + heirType = HEIR_TOKENS; + } + else { + return (uint8_t)0; + } + } + return DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, noLogging); +} + +// overload to decode opret in fundingtxid: +uint8_t DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { + uint256 dummyFundingTxidInOpret; + uint8_t dummyHasHeirSpendingBegun; + + return _DecodeHeirEitherOpret(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging); +} + +// overload to decode opret in A and C heir tx: +uint8_t DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t hasHeirSpendingBegun, bool noLogging) { + CPubKey dummyOwnerPubkey, dummyHeirPubkey; + int64_t dummyInactivityTime; + std::string dummyHeirName; + + return _DecodeHeirEitherOpret(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); +} /** * find the latest funding tx: it may be the first F tx or one of A or C tx's @@ -1042,14 +1028,6 @@ UniValue HeirInfo(uint256 fundingtxid) UniValue result(UniValue::VOBJ); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey ownerPubkey, heirPubkey; - uint256 latestFundingTxid; - uint256 dummyTokenid, tokenid; - - std::string heirName; - uint8_t funcId; - int64_t inactivityTimeSec; - CTransaction fundingtx; uint256 hashBlock; const bool allowSlow = false; @@ -1061,23 +1039,18 @@ UniValue HeirInfo(uint256 fundingtxid) // get initial funding tx and set it as initial lasttx: if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { + CPubKey ownerPubkey, heirPubkey; + uint256 latestFundingTxid; + uint256 dummyTokenid, tokenid = zeroid; + std::string heirName; + int64_t inactivityTimeSec; const bool noLogging = false; - uint8_t evalCodeTokens = 0; - std::vector voutPubkeys; - std::vector vopretExtra; - CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; - int32_t heirType = HEIR_COINS; - uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); - if (funcId != 0) { - heirScript = CScript(vopretExtra); - heirType = HEIR_TOKENS; - } - funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); - - if( funcId == 0 ) { - std::cerr << "HeirInfo() initial tx F not found for this fundingtx" << std::endl; + CScript opret = fundingtx.vout.size() > 0 ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); + uint8_t funcId = DecodeHeirEitherOpret(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); + if (funcId == 0) { + std::cerr << "HeirInfo() this fundingtx is incorrect" << std::endl; result.push_back(Pair("result", "error")); result.push_back(Pair("error", "initial tx F not found")); return result; @@ -1088,10 +1061,10 @@ UniValue HeirInfo(uint256 fundingtxid) uint8_t hasHeirSpendingBegun = 0; - if (heirType == HEIR_COINS) - latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); - else - latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + if (tokenid == zeroid) // coins + latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + else // tokens + latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); if (latestFundingTxid != zeroid) { int32_t numblocks; @@ -1105,7 +1078,7 @@ UniValue HeirInfo(uint256 fundingtxid) result.push_back(Pair("fundingtxid", fundingtxid.GetHex())); result.push_back(Pair("name", heirName.c_str())); - if (heirType == HEIR_TOKENS) { + if (tokenid != zeroid) { // tokens stream << tokenid.GetHex(); msg = "tokenid"; result.push_back(Pair(msg, stream.str().c_str())); @@ -1125,12 +1098,12 @@ UniValue HeirInfo(uint256 fundingtxid) stream.clear(); int64_t total; - if (heirType == HEIR_COINS) + if (tokenid != zeroid) total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); else total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); - if (heirType == HEIR_COINS) { + if (tokenid == zeroid) { msg = "funding total in coins"; stream << (double)total / COIN; } @@ -1143,12 +1116,12 @@ UniValue HeirInfo(uint256 fundingtxid) stream.clear(); int64_t inputs; - if (heirType == HEIR_COINS) + if (tokenid == zeroid) inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60); //NOTE: amount = 0 means all unspent inputs else inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60); - if (heirType == HEIR_COINS) { + if (tokenid == zeroid) { msg = "funding available in coins"; stream << (double)inputs / COIN; } @@ -1160,7 +1133,7 @@ UniValue HeirInfo(uint256 fundingtxid) stream.str(""); stream.clear(); - if (heirType == HEIR_TOKENS) { + if (tokenid != zeroid) { int64_t ownerInputs = TokenHelper::addOwnerInputs(cp, tokenid, mtx, ownerPubkey, 0, (int32_t)64); stream << ownerInputs; msg = "owner funding available in tokens"; diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 88d1d2745..5f56514d5 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -20,6 +20,8 @@ CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpen template 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, 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'); } From 7b7b5bdbc0095f3a4f625a669412a0607d425f1e Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 17:09:11 +0500 Subject: [PATCH 043/106] corr encode token opret plus no opcode cscript --- src/cc/CCtokens.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 553f61163..abcae84cd 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -78,7 +78,9 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t // if (payload.size() > 0) // opret += payload; --> "error 64: scriptpubkey" // TODO: check or serialization to vpayload! - return opret + payload; + CScript opretPayloadNoOpcode(vpayload); + + return opret + opretPayloadNoOpcode; } From 400b798cd242ec110a34a4e82597ba6896681509 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 17:41:41 +0500 Subject: [PATCH 044/106] try to add second opret w/o serialization --- src/cc/CCtokens.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index abcae84cd..917487bbe 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -71,16 +71,25 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ if (ccType >= 1) ss << voutPubkeys[0]; \ - if (ccType == 2) ss << voutPubkeys[1];); // \ - //if (vpayload.size() > 0) ss << vpayload;); + if (ccType == 2) ss << voutPubkeys[1]; ); // \ + // if (vpayload.size() > 0) ss << vpayload;); -// if (payload.size() > 0) -// opret += payload; --> "error 64: scriptpubkey" - // TODO: check or serialization to vpayload! - CScript opretPayloadNoOpcode(vpayload); + // "error 64: scriptpubkey": + // if (payload.size() > 0) + // opret += payload; - return opret + opretPayloadNoOpcode; + // error 64: scriptpubkey: + // CScript opretPayloadNoOpcode(vpayload); + // return opret + opretPayloadNoOpcode; + + // how to attach payload without re-serialization: + opret.resize(opret.size() + vpayload.size()); + CScript::iterator it = opret.begin() + opret.size(); + for (int i = 0; i < vpayload.size(); i++) + *it = vpayload[i]; + + return opret; } From ab87b673eb692ea3ae897ca3902d28e21a4fd0e1 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 17:48:03 +0500 Subject: [PATCH 045/106] iterator increment corr --- src/cc/CCtokens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 917487bbe..3bd94f19d 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -86,7 +86,7 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t // how to attach payload without re-serialization: opret.resize(opret.size() + vpayload.size()); CScript::iterator it = opret.begin() + opret.size(); - for (int i = 0; i < vpayload.size(); i++) + for (int i = 0; i < vpayload.size(); i++, it++) *it = vpayload[i]; return opret; From 39731c231f9728311a4ac382461cd8a5fa363d68 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 18:06:41 +0500 Subject: [PATCH 046/106] try to construct secod opret w/o serialization --- src/cc/CCtokens.cpp | 13 +++++++------ src/cc/heir.cpp | 15 ++++++++++----- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 3bd94f19d..c759f3704 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -71,8 +71,8 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t opret << OP_RETURN << E_MARSHAL(ss << evalCodeInOpret << tokenFuncId << tokenid << ccType; \ if (ccType >= 1) ss << voutPubkeys[0]; \ - if (ccType == 2) ss << voutPubkeys[1]; ); // \ - // if (vpayload.size() > 0) ss << vpayload;); + if (ccType == 2) ss << voutPubkeys[1]; \ + if (vpayload.size() > 0) ss << vpayload;); // "error 64: scriptpubkey": @@ -84,10 +84,11 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t // return opret + opretPayloadNoOpcode; // how to attach payload without re-serialization: - opret.resize(opret.size() + vpayload.size()); - CScript::iterator it = opret.begin() + opret.size(); - for (int i = 0; i < vpayload.size(); i++, it++) - *it = vpayload[i]; + // sig_aborted: + // opret.resize(opret.size() + vpayload.size()); + // CScript::iterator it = opret.begin() + opret.size(); + // for (int i = 0; i < vpayload.size(); i++, it++) + // *it = vpayload[i]; return opret; } diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 4276fee16..bdc485c5d 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -408,18 +408,23 @@ uint8_t _DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& { uint8_t evalCodeTokens = 0; std::vector voutPubkeys; - std::vector vopretExtra; + std::vector vopretExtra, vopretStripped; CScript heirScript = scriptPubKey; - int32_t heirType = HEIR_COINS; if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra) != 0) { if (vopretExtra.size() > 1) { // restore the second opret: heirScript = CScript(); - std::vector vopretStripped = std::vector(vopretExtra.begin()+1, vopretExtra.end()); //strip string size - heirScript << OP_RETURN << E_MARSHAL(ss << vopretStripped); - heirType = HEIR_TOKENS; + + E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; }); // std::vector(vopretExtra.begin()+1, vopretExtra.end()); //strip string size + + heirScript << OP_RETURN; + uint32_t i = heirScript.size(); + heirScript << E_MARSHAL(ss << vopretStripped); + for (uint32_t iStripped = 0; iStripped < vopretStripped.size(); iStripped++) + heirScript[i] = vopretStripped[iStripped]; + heirScript.resize(heirScript.size()-1); } else { return (uint8_t)0; From 97a030d05ad7f5b92c33fa621ffdb18ec2646ed4 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 22:38:33 +0500 Subject: [PATCH 047/106] corrected passing vopretStripped to DecodeHeirOpRet (instead CScript) --- src/cc/heir.cpp | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index bdc485c5d..b0272542c 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -322,22 +322,15 @@ CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpe return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << fundingtxid << hasHeirSpendingBegun); } -/** -* decode opret vout for Heir contract -*/ -uint8_t _DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) + +// decode opret vout for Heir contract +uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { - std::vector vopret; uint8_t evalCodeInOpret = 0; uint8_t heirFuncId = 0; fundingTxidInOpret = zeroid; //to init - GetOpReturnData(scriptPubKey, vopret); - if (vopret.size() == 0) { - if (!noLogging) std::cerr << "_DecodeHeirOpRet() warning: empty opret" << std::endl; - return (uint8_t)0; - } evalCodeInOpret = vopret.begin()[0]; if (vopret.size() > 1 && evalCodeInOpret == EVAL_HEIR) { @@ -387,8 +380,14 @@ uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& hei { uint256 dummytxid; uint8_t dummyHasHeirSpendingBegun; + std::vector vopret; - return _DecodeHeirOpRet(scriptPubKey, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging); + GetOpReturnData(scriptPubKey, vopret); + if (vopret.size() == 0) { + if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl; + return (uint8_t)0; + } + return _DecodeHeirOpRet(vopret, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging); } /** @@ -399,8 +398,15 @@ uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8 CPubKey dummyOwnerPubkey, dummyHeirPubkey; int64_t dummyInactivityTime; std::string dummyHeirName; + std::vector vopret; - return _DecodeHeirOpRet(scriptPubKey, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); + GetOpReturnData(scriptPubKey, vopret); + if (vopret.size() == 0) { + if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl; + return (uint8_t)0; + } + + return _DecodeHeirOpRet(vopret, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); } // decode combined opret: @@ -417,20 +423,17 @@ uint8_t _DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& // restore the second opret: heirScript = CScript(); - E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; }); // std::vector(vopretExtra.begin()+1, vopretExtra.end()); //strip string size - - heirScript << OP_RETURN; - uint32_t i = heirScript.size(); - heirScript << E_MARSHAL(ss << vopretStripped); - for (uint32_t iStripped = 0; iStripped < vopretStripped.size(); iStripped++) - heirScript[i] = vopretStripped[iStripped]; - heirScript.resize(heirScript.size()-1); + if (E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size + if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl; + return (uint8_t)0; + } } else { + if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl; return (uint8_t)0; } } - return DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, noLogging); + return _DecodeHeirOpRet(vopretStripped, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); } // overload to decode opret in fundingtxid: From d41cd8b99178036aeca822a3bd2cfe143b94a593 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sun, 13 Jan 2019 23:07:31 +0500 Subject: [PATCH 048/106] corr unmarshal retcode proc in _DecodeHeirEitherOpRet GetTokenBalance returns error always, obsolete --- src/cc/CCtokens.cpp | 7 +++++-- src/cc/heir.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index c759f3704..70aa60d92 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -661,7 +661,10 @@ int64_t GetTokenBalance(CPubKey pk, uint256 tokenid) CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CTransaction tokentx; - if (GetTransaction(tokenid, tokentx, hashBlock, false) == 0) + CCerror = strprintf("obsolete, cannot return correct value without eval"); + return 0; + +/* if (GetTransaction(tokenid, tokentx, hashBlock, false) == 0) { fprintf(stderr, "cant find tokenid\n"); CCerror = strprintf("cant find tokenid"); @@ -670,7 +673,7 @@ int64_t GetTokenBalance(CPubKey pk, uint256 tokenid) struct CCcontract_info *cp, C; cp = CCinit(&C, EVAL_TOKENS); - return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0)); + return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0)); */ } UniValue TokenInfo(uint256 tokenid) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index b0272542c..1d74b4970 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -423,7 +423,7 @@ uint8_t _DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& // restore the second opret: heirScript = CScript(); - if (E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size + if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl; return (uint8_t)0; } From 1a5999e0bdd0aeda5d42e4e14d274d696b5cea28 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 00:30:42 +0500 Subject: [PATCH 049/106] _DecodeHeirEitherOpRet corrected vopretStripped proc --- src/cc/heir.cpp | 84 ++++++++++++++----------------------------------- 1 file changed, 24 insertions(+), 60 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 1d74b4970..909d660d6 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -410,18 +410,15 @@ uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8 } // decode combined opret: -uint8_t _DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) +uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { uint8_t evalCodeTokens = 0; - std::vector voutPubkeys; + std::vector voutPubkeysDummy; std::vector vopretExtra, vopretStripped; - CScript heirScript = scriptPubKey; - - if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra) != 0) { + if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, vopretExtra) != 0) { if (vopretExtra.size() > 1) { // restore the second opret: - heirScript = CScript(); if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl; @@ -433,24 +430,28 @@ uint8_t _DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& return (uint8_t)0; } } + else + GetOpReturnData(scriptPubKey, vopretStripped); + return _DecodeHeirOpRet(vopretStripped, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); + } // overload to decode opret in fundingtxid: -uint8_t DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { +uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { uint256 dummyFundingTxidInOpret; uint8_t dummyHasHeirSpendingBegun; - return _DecodeHeirEitherOpret(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging); + return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging); } // overload to decode opret in A and C heir tx: -uint8_t DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t hasHeirSpendingBegun, bool noLogging) { +uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t hasHeirSpendingBegun, bool noLogging) { CPubKey dummyOwnerPubkey, dummyHeirPubkey; int64_t dummyInactivityTime; std::string dummyHeirName; - return _DecodeHeirEitherOpret(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); + return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); } /** @@ -472,22 +473,9 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ // get initial funding tx and set it as initial lasttx: if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { - uint256 dummytxid; - uint8_t evalCodeTokens = 0; - std::vector vopretExtra; - std::vector dummyVoutPubkeys; - - CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; - if (typeid(Helper) == typeid(TokenHelper)) { - if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { - heirScript = CScript(vopretExtra); - } - else { - std::cerr << "FindLatestFundingTx() could not decode token opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n'; - return zeroid; - } - } - funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName); + CScript heirScript = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); + + uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); if (funcId != 0) { // found at least funding tx! //std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n'; @@ -522,48 +510,24 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ //std::cerr << "FindLatestFundingTx() checking unspents for txid=" << txid.GetHex() << '\n'; int32_t blockHeight = (int32_t)it->second.blockHeight; - uint256 fundingTxidInOpret; //NOTE: maybe called from validation code: if (myGetTransaction(txid, regtx, hash)) { //std::cerr << "FindLatestFundingTx() found tx for txid=" << txid.GetHex() << " blockHeight=" << blockHeight << " maxBlockHeight=" << maxBlockHeight << '\n'; - - /*{ // debug code: - uint256 debAssetid; - uint8_t debHasHeirSpendingBegun; - uint8_t debfuncid = DecodeHeirOpRet(regtx.vout[regtx.vout.size() - 1].scriptPubKey, debAssetid, fundingTxidInOpret, debHasHeirSpendingBegun, true); - - std::cerr << "FindLatestFundingTx() regtx.vout.size()=" << regtx.vout.size() << " funcId=" << (char)(debfuncid ? debfuncid : ' ') - << " tokenid=" << debAssetid.GetHex() << " fundingtxidInOpret=" << fundingTxidInOpret.GetHex() << " debHasHeirSpendingBegun=" << (int)debHasHeirSpendingBegun << std::endl; - }*/ - - uint256 dummyTokenid; // not to contaminate the tokenid from the params! + uint256 fundingTxidInOpret; + uint256 tokenidInOpret; // not to contaminate the tokenid from the params! uint8_t tmpFuncId; - uint8_t tmphasHeirSpendingBegun; + uint8_t hasHeirSpendingBegunInOpret; - uint8_t evalCodeTokens = 0; - std::vector vopretExtra; - std::vector dummyVoutPubkeys; - - CScript heirScript = regtx.vout[regtx.vout.size() - 1].scriptPubKey; - if (typeid(Helper) == typeid(TokenHelper)) { - if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { - heirScript = CScript(vopretExtra); - } - else { - std::cerr << "FindLatestFundingTx() could not decode token opreturn for fundingtxid=" << fundingtxid.GetHex() << '\n'; - return zeroid; - } - } - tmpFuncId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, tmphasHeirSpendingBegun, true); - - if (regtx.vout.size() > 0 && tmpFuncId != 0 && fundingtxid == fundingTxidInOpret) { + CScript heirScript = (regtx.vout.size() > 0) ? regtx.vout[regtx.vout.size() - 1].scriptPubKey : CScript(); + tmpFuncId = DecodeHeirEitherOpRet(heirScript, tokenidInOpret, fundingTxidInOpret, hasHeirSpendingBegunInOpret, true); + if (tmpFuncId != 0 && fundingtxid == fundingTxidInOpret && (tokenid == zeroid || tokenid == tokenidInOpret)) { // check tokenid also if (blockHeight > maxBlockHeight) { maxBlockHeight = blockHeight; latesttxid = txid; funcId = tmpFuncId; - hasHeirSpendingBegun = tmphasHeirSpendingBegun; + hasHeirSpendingBegun = hasHeirSpendingBegunInOpret; //std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight // << " opreturn type=" << (char)(funcId ? funcId : ' ') << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << " - set as current lasttxid" << '\n'; @@ -1049,14 +1013,14 @@ UniValue HeirInfo(uint256 fundingtxid) CPubKey ownerPubkey, heirPubkey; uint256 latestFundingTxid; - uint256 dummyTokenid, tokenid = zeroid; + uint256 dummyTokenid, tokenid = zeroid; // important to clear tokenid std::string heirName; int64_t inactivityTimeSec; const bool noLogging = false; CScript opret = fundingtx.vout.size() > 0 ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); - uint8_t funcId = DecodeHeirEitherOpret(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); + uint8_t funcId = DecodeHeirEitherOpret(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true); if (funcId == 0) { std::cerr << "HeirInfo() this fundingtx is incorrect" << std::endl; result.push_back(Pair("result", "error")); @@ -1072,7 +1036,7 @@ UniValue HeirInfo(uint256 fundingtxid) if (tokenid == zeroid) // coins latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); else // tokens - latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid /*<-verify for tokens*/, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); if (latestFundingTxid != zeroid) { int32_t numblocks; From 42a48b9653241c07e60d821f2e79e89ae1c0947f Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 00:38:56 +0500 Subject: [PATCH 050/106] corrected call to DecodeHeirEitherOpRet in Heirinfo --- src/cc/heir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 909d660d6..a895c9cc2 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -446,7 +446,7 @@ uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& o } // overload to decode opret in A and C heir tx: -uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t hasHeirSpendingBegun, bool noLogging) { +uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { CPubKey dummyOwnerPubkey, dummyHeirPubkey; int64_t dummyInactivityTime; std::string dummyHeirName; @@ -1020,7 +1020,7 @@ UniValue HeirInfo(uint256 fundingtxid) CScript opret = fundingtx.vout.size() > 0 ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); - uint8_t funcId = DecodeHeirEitherOpret(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true); + uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true); if (funcId == 0) { std::cerr << "HeirInfo() this fundingtx is incorrect" << std::endl; result.push_back(Pair("result", "error")); From 5c35c03d60c68d9cb1db430c2f9492b4c537144d Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 01:27:45 +0500 Subject: [PATCH 051/106] added isTokenVout call to Add1of2address func in heir.cpp corrected ExtractTokensVinPubkeys call -> in isTokensVout --- src/cc/CCtokens.cpp | 16 +++++++++++----- src/cc/heir.cpp | 16 +++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 70aa60d92..9b110992b 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -262,14 +262,17 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & // helper funcs: // extract my vins pubkeys: -bool ExtractVinPubkeys(struct CCcontract_info *cp, CTransaction tx, std::vector &vinPubkeys) { +bool ExtractTokensVinPubkeys(CTransaction tx, std::vector &vinPubkeys) { bool found = false; CPubKey pubkey; + struct CCcontract_info *cpTokens, tokensC; + + cpTokens = CCinit(&tokensC, EVAL_TOKENS); 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) ) + if( (*cpTokens->ismyvin)(tx.vin[i].scriptSig) ) { auto findEval = [](CC *cond, struct CCVisitor _) { @@ -345,7 +348,7 @@ uint8_t ValidateTokenOpret(CTransaction tx, int32_t v, uint256 tokenid, std::vec // goDeeper is true: the func also validates amounts of the passed transaction: // it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx // checkPubkeys is true: validates if the vout is token vout1 or token vout1of2. Should always be true! -int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, /*std::vector &vopretExtra,*/ const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys) +int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, /*std::vector &vopretExtra,*/ const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys000) { // this is just for log messages indentation fur debugging recursive calls: @@ -421,6 +424,9 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c } // maybe it is token change? + std::vector vinPubkeys; + ExtractTokensVinPubkeys(tx, vinPubkeys); + for(std::vector::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) { CTxOut testVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, *it); @@ -450,7 +456,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t //int32_t flag; int64_t tokenoshis; // std::vector tmporigpubkey; int64_t tmpprice; - std::vector vinPubkeys, vinPubkeysEmpty; + std::vector vinPubkeys; int32_t numvins = tx.vin.size(); int32_t numvouts = tx.vout.size(); @@ -459,7 +465,7 @@ 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); + ExtractTokensVinPubkeys(tx, vinPubkeys); for (int32_t i = 0; i int64_t Add1of2AddressInputs(struct CCcontract_info* cp, if (GetTransaction(txid, heirtx, hashBlock, false) != 0) { uint256 tokenid; uint256 fundingTxidInOpret; - uint8_t dummyHasHeirSpendingBegun; - uint8_t evalCodeTokens = 0; - std::vector vopretExtra; - std::vector voutPubkeys; + uint8_t hasHeirSpendingBegunDummy; + std::vector vinPubkeysEmpty; - CScript heirScript = heirtx.vout[heirtx.vout.size() - 1].scriptPubKey; - uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); - if (funcId != 0) { - heirScript = CScript(vopretExtra); - } - funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); + CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); + uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, false); if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && funcId != 0 && isMyFuncId(funcId) && - // (typeid(Helper) == typeid(TokenHelper) && IsHeirvout(true, cp, nullptr, tokenid, vintx, voutIndex) > 0) && // deep validation for tokens - not used anymore + (typeid(Helper) == typeid(TokenHelper) && IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid, vinPubkeysEmpty) > 0) && // deep validation for tokens - not used anymore (voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && !myIsutxo_spentinmempool(txid, voutIndex)) { From dbae803774c362b6e1f903970aadbd8adb1844ed Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 01:39:56 +0500 Subject: [PATCH 052/106] added loggin into isTokensVout --- src/cc/CCtokens.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 9b110992b..447bb96f6 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -353,7 +353,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // this is just for log messages indentation fur debugging recursive calls: std::string indentStr = std::string().append(tokenValIndentSize, '.'); - //std::cerr << indentStr << "IsTokensvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for tokenid=" << reftokenid.GetHex() << std::endl; //TODO: validate cc vouts are EVAL_TOKENS! @@ -456,7 +456,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t //int32_t flag; int64_t tokenoshis; // std::vector tmporigpubkey; int64_t tmpprice; - std::vector vinPubkeys; + std::vector vinPubkeys000; int32_t numvins = tx.vin.size(); int32_t numvouts = tx.vout.size(); @@ -465,7 +465,7 @@ 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, '.'); - ExtractTokensVinPubkeys(tx, vinPubkeys); + //ExtractTokensVinPubkeys(tx, vinPubkeys); for (int32_t i = 0; iInvalid("always should find vin tx, but didnt"); - } else { tokenValIndentSize++; @@ -500,6 +501,7 @@ bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t tokenValIndentSize++; // Note: we pass in here 'false' because we don't need to call TokenExactAmounts() recursively from IsTokensvout // indeed, in this case we'll be checking this tx again + std::cerr << indentStr << "TokenExactAmounts() check vout i=" << i << " nValue=" << tx.vout[i].nValue << std::endl; tokenoshis = IsTokensvout(false, true /*<--exclude non-tokens vouts*/, cpTokens, eval,/* tmporigpubkey,*/ tx, i, tokenid, vinPubkeys000); tokenValIndentSize--; From d3c804c50c8e84e4ea1d1da0187f7a2272f09fe1 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 13:10:18 +0500 Subject: [PATCH 054/106] corr DecodeHeirEitherOpRet call in LifeTimeHeirContractFund restores !ismempool.. check --- src/cc/heir.cpp | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index dff407aac..9b78f2584 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -593,14 +593,14 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, uint8_t hasHeirSpendingBegunDummy; std::vector vinPubkeysEmpty; - CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); + CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); // check boundary uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, false); if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && funcId != 0 && isMyFuncId(funcId) && - (typeid(Helper) == typeid(TokenHelper) && IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid, vinPubkeysEmpty) > 0) && // deep validation for tokens - not used anymore - (voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && + (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid, vinPubkeysEmpty) > 0) && // token validation logic + //(voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && // heir contract vout validation logic - not used since we moved to 2-eval vouts !myIsutxo_spentinmempool(txid, voutIndex)) { std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; @@ -633,28 +633,26 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info for (std::vector>::const_iterator it = addressIndexes.begin(); it != addressIndexes.end(); it++) { uint256 hashBlock; uint256 txid = it->first.txhash; - CTransaction tx; + CTransaction heirtx; - if (GetTransaction(txid, tx, hashBlock, false) && tx.vout.size() > 0) { - uint8_t evalCodeTokens = 0; + // TODO: check all funding tx should contain unspendable markers + if (GetTransaction(txid, heirtx, hashBlock, false) && heirtx.vout.size() > 0) { uint256 tokenid; uint256 fundingTxidInOpret; - std::vector vopretExtra; - std::vector voutPubkeys; - uint8_t dummyHasHeirSpendingBegun; + uint8_t hasHeirSpendingBegunDummy; + std::vector vinPubkeysEmpty; const int32_t ivout = 0; - CScript heirScript = tx.vout[tx.vout.size() - 1].scriptPubKey; - uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); - if (funcId != 0) { - heirScript = CScript(vopretExtra); - } - funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); + CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); // check boundary + uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, false); //std::cerr << "LifetimeHeirContractFunds() found tx=" << txid.GetHex() << " vout[0].nValue=" << subtx.vout[ccVoutIdx].nValue << " opreturn=" << (char)funcId << '\n'; - if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && isMyFuncId(funcId) && !isSpendingTx(funcId) - /* && !myIsutxo_spentinmempool(txid, ccVoutIdx) */) // include also tx in mempool + if (funcId != 0 && + (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && + isMyFuncId(funcId) && !isSpendingTx(funcId) && + (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, ivout, tokenid, vinPubkeysEmpty) > 0) && + !myIsutxo_spentinmempool(txid, ivout)) // exclude tx in mempool { total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change) //std::cerr << "LifetimeHeirContractFunds() added tx=" << txid.GetHex() << " it->second=" << it->second << " vout[0].nValue=" << tx.vout[ivout].nValue << " opreturn=" << (char)funcId << '\n'; From 08c0a5a8c6238e2f6770b98bfa82ab2b64d73165 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 13:23:08 +0500 Subject: [PATCH 055/106] corr "is token" check in HeirInfo --- src/cc/heir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 9b78f2584..6fd98d545 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -603,7 +603,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, //(voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && // heir contract vout validation logic - not used since we moved to 2-eval vouts !myIsutxo_spentinmempool(txid, voutIndex)) { - std::cerr << "Add1of2AddressInputs() voutValue=" << voutValue << " satoshis=" << it->second.satoshis << '\n'; + std::cerr << "Add1of2AddressInputs() satoshis=" << it->second.satoshis << std::endl; if (total != 0 && maxinputs != 0) mtx.vin.push_back(CTxIn(txid, voutIndex, CScript())); nValue = it->second.satoshis; @@ -1062,7 +1062,7 @@ UniValue HeirInfo(uint256 fundingtxid) stream.clear(); int64_t total; - if (tokenid != zeroid) + if (tokenid == zeroid) total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); else total = LifetimeHeirContractFunds(cp, fundingtxid, ownerPubkey, heirPubkey); From 1fb94e5a34c63ae306cc2741fe77a0314e03a9b8 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 17:26:42 +0500 Subject: [PATCH 056/106] corr DecodeHeirEitherOpRet in validators added EVAL_TOKENS check in DecodeTokenOpRet --- src/cc/CCtokens.cpp | 3 ++ src/cc/heir.cpp | 100 ++++++++--------------------------------- src/cc/heir_validate.h | 94 +++++--------------------------------- 3 files changed, 33 insertions(+), 164 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index a95ef2dd8..242b0a38e 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -125,6 +125,9 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 bool isEof = true; evalCode = script[0]; + if (evalCode != EVAL_TOKENS) + return (uint8_t)0; + funcId = script[1]; //fprintf(stderr,"decode.[%c]\n",funcId); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 6fd98d545..c982fb193 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -125,23 +125,10 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenid = zeroid; CScript fundingTxOpRetScript; - uint8_t hasHeirSpendingBegun = 0, dummyHasHeirSpendingBegun; + uint8_t hasHeirSpendingBegun = 0, hasHeirSpendingBegunDummy; - - uint8_t evalCodeTokens = 0; - std::vector voutPubkeys; - std::vector vopretExtra; - - CScript heirScript = tx.vout[tx.vout.size() - 1].scriptPubKey; - int32_t heirType = HEIR_COINS; - - uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); - if (funcId != 0) { - heirScript = CScript(vopretExtra); - heirType = HEIR_TOKENS; - } - funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyHasHeirSpendingBegun, true); - + CScript opret = (tx.vout.size() > 0) ? tx.vout[tx.vout.size() - 1].scriptPubKey : CScript(); // check boundary + uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, true); if (funcId == 0) return eval->Invalid("invalid opreturn format"); @@ -149,7 +136,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction if (fundingTxidInOpret == zeroid) { return eval->Invalid("invalid tx opreturn format: no fundingtxid present"); } - if (heirType == HEIR_COINS) + if (tokenid == zeroid) latestTxid = FindLatestFundingTx(fundingTxidInOpret, dummyTokenid, fundingTxOpRetScript, hasHeirSpendingBegun); else latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, hasHeirSpendingBegun); @@ -159,7 +146,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction } } else { - fundingTxOpRetScript = tx.vout[numvouts - 1].scriptPubKey; + fundingTxOpRetScript = opret; } std::cerr << "HeirValidate funcid=" << (char)funcId << " evalcode=" << (int)cpHeir->evalcode << std::endl; @@ -185,7 +172,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction // vout.1: txfee for CC addr used as a marker // vout.2: normal change // vout.n-1: opreturn 't' tokenid 'F' ownerpk heirpk inactivitytime heirname tokenid - if (heirType == HEIR_TOKENS) + if (tokenid != zeroid) return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); else return eval->Invalid("unexpected HeirValidate for heirfund"); @@ -206,7 +193,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction // vout.0: funding CC 1of2 addr for the owner and heir // vout.1: normal change // vout.n-1: opreturn 't' tokenid 'A' ownerpk heirpk inactivitytime fundingtx - if (heirType == HEIR_TOKENS) + if (tokenid != zeroid) return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); else return eval->Invalid("unexpected HeirValidate for heiradd"); @@ -230,7 +217,7 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction // vout.1: change to CC 1of2 addr // vout.2: change to normal from txfee input if any // vout.n-1: opreturn 't' tokenid 'C' ownerpk heirpk inactivitytime fundingtx - if (heirType == HEIR_TOKENS) + if (tokenid != zeroid) return RunValidationPlans(funcId, cpTokens, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); else return RunValidationPlans(funcId, cpHeir, eval, tx, latestTxid, fundingTxOpRetScript, hasHeirSpendingBegun); @@ -267,44 +254,6 @@ template int64_t IsHeirFundingVout(struct CCcontract_info* cp, co return (0); } -// not used -bool HeirExactAmounts(struct CCcontract_info* cp, Eval* eval, const CTransaction& tx, int32_t minage, uint64_t txfee) -{ - static uint256 zerohash; - CTransaction vinTx; - uint256 hashBlock, activehash; - int32_t i, numvins, numvouts; - int64_t inputs = 0, outputs = 0, assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); - for (i = 0; i < numvins; i++) { - //fprintf(stderr,"HeirExactAmounts() vini.%d\n",i); - if ((*cp->ismyvin)(tx.vin[i].scriptSig) != 0) { - //fprintf(stderr,"HeirExactAmounts() vini.%d check mempool\n",i); - if (eval->GetTxUnconfirmed(tx.vin[i].prevout.hash, vinTx, hashBlock) == 0) - return eval->Invalid("cant find vinTx"); - else { - //fprintf(stderr,"HeirExactAmounts() vini.%d check hash and vout\n",i); - if (hashBlock == zerohash) - return eval->Invalid("cant Heir from mempool"); - ////if ( (assetoshis= IsHeirCCvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) - //// inputs += assetoshis; - } - } - } - for (i = 0; i < numvouts; i++) { - //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts); - ////if ( (assetoshis= IsHeirvout(cp,tx,i)) != 0 ) - //// outputs += assetoshis; - } - if (inputs != outputs + txfee) { - fprintf(stderr, "HeirExactAmounts() inputs %llu vs outputs %llu\n", (long long)inputs, (long long)outputs); - return eval->Invalid("mismatched inputs != outputs + txfee"); - } - else - return (true); -} - // makes coin initial tx opret CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { @@ -373,9 +322,8 @@ uint8_t _DecodeHeirOpRet(std::vector vopret, CPubKey& ownerPubkey, CPub return (uint8_t)0; } -/** -* overload for 'F' opret -*/ +/* not used, see DecodeHeirOpRet(vopret,...) +// overload for 'F' opret uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) { uint256 dummytxid; @@ -388,11 +336,11 @@ uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& hei return (uint8_t)0; } return _DecodeHeirOpRet(vopret, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging); -} +}*/ -/** -* overload for A, C oprets and AddHeirContractInputs -*/ + +/* not used, see DecodeHeirOpRet(vopret,...) +// overload for A, C oprets and AddHeirContractInputs uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) { CPubKey dummyOwnerPubkey, dummyHeirPubkey; @@ -407,7 +355,7 @@ uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8 } return _DecodeHeirOpRet(vopret, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging); -} +} */ // decode combined opret: uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) @@ -473,8 +421,8 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ // get initial funding tx and set it as initial lasttx: if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { - CScript heirScript = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); + CScript heirScript = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); if (funcId != 0) { // found at least funding tx! @@ -979,8 +927,6 @@ UniValue HeirClaimTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amoun return HeirClaim(fundingtxid, txfee, amount); } - - /** * heirinfo rpc call implementation * returns some information about heir CC contract plan by a handle of initial fundingtxid: @@ -1160,23 +1106,15 @@ template void _HeirList(struct CCcontract_info *cp, UniValue &r //std::cerr << "HeirList() checking txid=" << txid.GetHex() << " vout=" << vout << '\n'; CTransaction fundingtx; - if (GetTransaction(txid, fundingtx, hashBlock, false) != 0 && (fundingtx.vout.size() - 1) > 0) { + if (GetTransaction(txid, fundingtx, hashBlock, false)) { CPubKey ownerPubkey, heirPubkey; std::string heirName; int64_t inactivityTimeSec; const bool noLogging = true; - - uint8_t evalCodeTokens = 0; uint256 tokenid; - std::vector vopretExtra; - std::vector voutPubkeys; - CScript heirScript = fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey; - uint8_t funcId = DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, voutPubkeys, vopretExtra); - if (funcId != 0) { - heirScript = CScript(vopretExtra); - } - funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, noLogging); + CScript opret = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); + uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true); // note: if it is not Heir token funcId would be equal to 0 if (funcId == 'F') { diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 5f56514d5..2bcc96b9e 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -4,29 +4,21 @@ #include "CCinclude.h" #include "CCHeir.h" -#define NOT_HEIR (-1) -#define HEIR_COINS 1 -#define HEIR_TOKENS 2 #define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos) - // makes coin initial tx opret CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); -// makes token opret -//CScript EncodeHeirTokensCreateOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string hearName); -//CScript EncodeHeirTokensOpRet(uint8_t funcid, uint256 tokenid, std::vector voutPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan); template 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, bool noLogging = false); -uint8_t DecodeHeirEitherOpret(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t hasHeirSpendingBegun, bool noLogging = false); +//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, 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: @@ -411,22 +403,7 @@ public: std::string heirName; uint256 tokenid; - uint8_t evalCodeTokens = 0; - std::vector vopretExtra; - std::vector dummyVoutPubkeys; - - CScript heirScript = m_fundingOpretScript; - if (typeid(Helper) == typeid(TokenHelper)) { - if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { - heirScript = CScript(vopretExtra); - } - else { - message = m_customMessage + std::string(" invalid token opreturn format"); - std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; - return false; - } - } - uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false); + uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); if (funcId == 0) { message = m_customMessage + std::string(" invalid opreturn format"); std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; @@ -481,28 +458,15 @@ public: ///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl; - uint8_t evalCodeTokens = 0; - std::vector vopretExtra; - std::vector dummyVoutPubkeys; - - CScript ownerScript; - CScript heirScript = m_fundingOpretScript; - if (typeid(Helper) == typeid(TokenHelper)) { - if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { - heirScript = CScript(vopretExtra); - } - else { - message = std::string("invalid token opreturn format"); - return false; - } - } // get both pubkeys: - uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false); + uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); if (funcId == 0) { message = std::string("invalid opreturn format"); return false; } + CScript ownerScript; + CScript heirScript; if (m_checkNormals) { ownerScript = CoinHelper::makeUserVout(vout.nValue, ownerPubkey).scriptPubKey; heirScript = CoinHelper::makeUserVout(vout.nValue, heirPubkey).scriptPubKey; @@ -552,22 +516,8 @@ public: std::string heirName; uint256 tokenid; - uint8_t evalCodeTokens = 0; - std::vector vopretExtra; - std::vector dummyVoutPubkeys; - - CScript heirScript = m_fundingOpretScript; - if (typeid(Helper) == typeid(TokenHelper)) { - if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { - heirScript = CScript(vopretExtra); - } else { - message = std::string("invalid token opreturn format"); - return false; - } - } - // get heir pubkey: - uint8_t funcId = DecodeHeirOpRet(heirScript, ownerPubkey, heirPubkey, inactivityTime, heirName, false); + uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true); if (funcId == 0) { message = std::string("invalid opreturn format"); return false; @@ -620,35 +570,13 @@ public: uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid; uint8_t dummyIsHeirSpendingBegan; - uint8_t evalCodeTokens = 0; - std::vector vopretExtra; - std::vector dummyVoutPubkeys; - - CScript heirScript = vout.scriptPubKey; - if (typeid(Helper) == typeid(TokenHelper)) { - if (DecodeTokenOpRet(heirScript, evalCodeTokens, tokenid, dummyVoutPubkeys, vopretExtra) != 0) { - heirScript = CScript(vopretExtra); - } else { - message = std::string("invalid token opreturn format"); - return false; - } - } - uint8_t funcId = DecodeHeirOpRet(heirScript, fundingTxidInOpret, dummyIsHeirSpendingBegan); + uint8_t funcId = DecodeHeirEitherOpRet(vout.scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true); if (funcId == 0) { message = std::string("invalid opreturn format"); return false; } - heirScript = m_fundingOpretScript; - if (typeid(Helper) == typeid(TokenHelper)) { - if (DecodeTokenOpRet(heirScript, evalCodeTokens, initialTokenid, dummyVoutPubkeys, vopretExtra) != 0) { - heirScript = CScript(vopretExtra); - } else { - message = std::string("invalid initial token opreturn format"); - return false; - } - } - uint8_t initialFuncId = DecodeHeirOpRet(heirScript, dummyTxid, dummyIsHeirSpendingBegan); + uint8_t initialFuncId = DecodeHeirEitherOpRet(m_fundingOpretScript, initialTokenid, dummyTxid, dummyIsHeirSpendingBegan, true); if (initialFuncId == 0) { message = std::string("invalid initial tx opreturn format"); return false; From fd0c4b89789cd99fc94b1e962291737607e4ef07 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 21:42:37 +0500 Subject: [PATCH 057/106] corr CCinit in HeirAdd HeirClaim --- src/cc/heir.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index c982fb193..1ed652efd 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -640,12 +640,12 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, int64_t inputs, change; if ((inputs=Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners - //mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,amount,HeirCCpk)); - mtx.vout.push_back(MakeTokensCC1of2vout(/*Helper::getMyEval()*/EVAL_HEIR, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk + //mtx.vout.push_back(MakeTokensCC1of2vout(/*Helper::getMyEval()*/EVAL_HEIR, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk + mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey)); // add a marker for finding all plans in HeirList() - CPubKey HeirContractPubKey = GetUnspendable(cp, 0); - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(HeirContractPubKey)) << OP_CHECKSIG)); // TODO: do we need this marker? + CPubKey heirUnspendablePubKey = GetUnspendable(cp, 0); + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(heirUnspendablePubKey)) << OP_CHECKSIG)); // TODO: do we need this marker? // calc and add change vout: if (inputs > amount) @@ -703,7 +703,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in uint8_t funcId; uint8_t hasHeirSpendingBegun = 0; - cp = CCinit(&C, EVAL_HEIR); + cp = CCinit(&C, Helper::getMyEval()); // for tokens shoud be EVAL_TOKENS to sign it correctly! if (txfee == 0) txfee = 10000; @@ -734,7 +734,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */ // add cryptocondition to spend this funded amount for either pk - mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! + mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); if (inputs > amount) change = (inputs - amount); // -txfee <-- txfee pays user @@ -807,8 +807,8 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee std::string heirName; uint8_t hasHeirSpendingBegun = 0; - cp = CCinit(&C, EVAL_HEIR); - if (txfee == 0) + cp = CCinit(&C, Helper::getMyEval()); + if (txfee == 0) txfee = 10000; if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { @@ -882,11 +882,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); Myprivkey(myprivkey); - ////fprintf(stderr,"HeirClaim() before setting unspendable CC addr2= (%s) addr3= (%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); - //CCaddr2set(cp, Helper::getMyEval(), ownerPubkey, myprivkey, coinaddr); - //CCaddr3set(cp, Helper::getMyEval(), heirPubkey, myprivkey, coinaddr); - ////fprintf(stderr, "HeirClaim() after setting unspendable CC addr2=(%s) addr3=(%s)\n", cp->unspendableaddr2, cp->unspendableaddr3); - + // set pubkeys for finding 1of2 cc in FinalizeCCtx to sign it: Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); // add 1of2 vout validation pubkeys (this is for tokens): From 99c5484b66643a047356df01ff1a36832b0f214f Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 22:04:50 +0500 Subject: [PATCH 058/106] corr cp usage in helper funcs --- src/cc/heir.cpp | 18 +++++++++--------- src/cc/heir_validate.h | 32 +++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 1ed652efd..97c89582f 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -517,7 +517,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, std::vector> unspentOutputs; char coinaddr[64]; - Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 of 2 pubkeys' + Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); // get address of cryptocondition '1 of 2 pubkeys' SetCCunspents(unspentOutputs, coinaddr); // char markeraddr[64]; @@ -571,7 +571,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, template int64_t LifetimeHeirContractFunds(struct CCcontract_info* cp, uint256 fundingtxid, CPubKey ownerPubkey, CPubKey heirPubkey) { char coinaddr[64]; - Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' + Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); // get the address of cryptocondition '1 of 2 pubkeys' std::vector> addressIndexes; SetCCtxids(addressIndexes, coinaddr); @@ -639,7 +639,7 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners int64_t inputs, change; - if ((inputs=Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners + if ((inputs=Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners //mtx.vout.push_back(MakeTokensCC1of2vout(/*Helper::getMyEval()*/EVAL_HEIR, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey)); @@ -724,7 +724,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in int64_t inputs, change; - if ((inputs = Helper::addOwnerInputs(cp, tokenid, mtx, myPubkey, amount, 64)) > 0) { // TODO: why 64 max inputs? + if ((inputs = Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, 64)) > 0) { // TODO: why 64 max inputs? // we do not use markers anymore - storing data in opreturn is better // add marker vout: @@ -758,9 +758,9 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in result.push_back(Pair("hextx", rawhextx)); } else { - std::cerr << "HeirAdd cannot find owner inputs" << std::endl; + std::cerr << "HeirAdd cannot find owner cc inputs" << std::endl; result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find owner inputs")); + result.push_back(Pair("error", "can't find owner cc inputs")); } } else { @@ -879,11 +879,11 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee uint8_t myprivkey[32]; char coinaddr[64]; // set priv key addresses in CC structure: - Helper::GetCoinsOrTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); Myprivkey(myprivkey); // set pubkeys for finding 1of2 cc in FinalizeCCtx to sign it: - Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + Helper::CCaddrCoinsOrTokens1of2set(ownerPubkey, heirPubkey, coinaddr); // add 1of2 vout validation pubkeys (this is for tokens): std::vector voutTokenPubkeys; @@ -1040,7 +1040,7 @@ UniValue HeirInfo(uint256 fundingtxid) stream.clear(); if (tokenid != zeroid) { - int64_t ownerInputs = TokenHelper::addOwnerInputs(cp, tokenid, mtx, ownerPubkey, 0, (int32_t)64); + int64_t ownerInputs = TokenHelper::addOwnerInputs(tokenid, mtx, ownerPubkey, 0, (int32_t)64); stream << ownerInputs; msg = "owner funding available in tokens"; result.push_back(Pair(msg, stream.str().c_str())); diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 2bcc96b9e..8f08a1588 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -24,7 +24,7 @@ class CoinHelper { public: static uint8_t getMyEval() { return EVAL_HEIR; } - static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { + static int64_t addOwnerInputs(uint256 dummyid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { return AddNormalinputs(mtx, ownerPubkey, total, maxinputs); } @@ -46,11 +46,15 @@ public: static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) { return CTxOut(amount, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG); } - static bool GetCoinsOrTokensCCaddress1of2(struct CCcontract_info* cp, char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) { - return GetCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + 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) { - CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + static void CCaddrCoinsOrTokens1of2set(CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { + struct CCcontract_info *cpHeir, heirC; + cpHeir = CCinit(&heirC, EVAL_HEIR); + CCaddr1of2set(cpHeir, ownerPubkey, heirPubkey, coinaddr); } }; @@ -58,8 +62,10 @@ public: class TokenHelper { public: static uint8_t getMyEval() { return EVAL_TOKENS; } - static int64_t addOwnerInputs(struct CCcontract_info* cp, uint256 tokenid, CMutableTransaction& mtx, CPubKey ownerPubkey, int64_t total, int32_t maxinputs) { - return AddTokenCCInputs(cp, mtx, ownerPubkey, tokenid, total, maxinputs); + 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_HEIR); + return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs); } static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { @@ -84,12 +90,16 @@ public: static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) { return MakeTokensCC1vout(EVAL_HEIR, amount, myPubkey); } - static bool GetCoinsOrTokensCCaddress1of2(struct CCcontract_info* cp, char *coinaddr, CPubKey ownerPubkey, CPubKey heirPubkey) { - return GetTokensCCaddress1of2(cp, coinaddr, ownerPubkey, heirPubkey); + 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) { - CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + static void CCaddrCoinsOrTokens1of2set(CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { + struct CCcontract_info *cpHeir, heirC; + cpHeir = CCinit(&heirC, EVAL_HEIR); + CCaddrTokens1of2set(cpHeir, ownerPubkey, heirPubkey, coinaddr); } }; From 849d60f4d975b03641909489a0555f7771555d69 Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 14 Jan 2019 22:11:24 +0500 Subject: [PATCH 059/106] eval changed back to EVAL_HEIR in CCinit in HeirAdd --- src/cc/heir.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 97c89582f..c87f8155d 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -437,6 +437,7 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ return zeroid; } + // TODO: correct cc addr: std::vector> unspentOutputs; struct CCcontract_info *cp, C; cp = CCinit(&C, EVAL_HEIR); @@ -703,7 +704,8 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in uint8_t funcId; uint8_t hasHeirSpendingBegun = 0; - cp = CCinit(&C, Helper::getMyEval()); // for tokens shoud be EVAL_TOKENS to sign it correctly! + //cp = CCinit(&C, Helper::getMyEval()); // for tokens shoud be EVAL_TOKENS to sign it correctly! + cp = CCinit(&C, EVAL_HEIR); // for tokens shoud be EVAL_TOKENS to sign it correctly! if (txfee == 0) txfee = 10000; From ec954480a871ce38801ad641d047764e51499c70 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 11:59:53 +0500 Subject: [PATCH 060/106] added more variants checking vouts in IsTokenVout corr vouts1 in Heir.cpp to single-eval token changed result type for HeirFund --- src/cc/CCHeir.h | 4 +-- src/cc/CCinclude.h | 1 + src/cc/CCtokens.cpp | 66 ++++++++++++++++++++++++++++------------ src/cc/heir.cpp | 55 +++++++++++++++++++++++---------- src/cc/heir_validate.h | 24 +++++++-------- src/wallet/rpcwallet.cpp | 12 ++++---- 6 files changed, 106 insertions(+), 56 deletions(-) diff --git a/src/cc/CCHeir.h b/src/cc/CCHeir.h index 18d1f08bb..8399474a7 100644 --- a/src/cc/CCHeir.h +++ b/src/cc/CCHeir.h @@ -34,8 +34,8 @@ class TokenHelper; //template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount); //template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t nValue); -std::string HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); -std::string HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); +UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); +UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); UniValue HeirClaimCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); UniValue HeirClaimTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); UniValue HeirAddCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index c42a4799e..14a500222 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -162,6 +162,7 @@ CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); +CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, CScript payload); CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector &voutPubkeys, std::vector &vopretExtra); diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 242b0a38e..d1dcf0b1f 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -51,14 +51,11 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid,std::vector origpubkey,st } // this is for other contracts which use tokens and build customized extra payloads to token's opret: -CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) +CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, CScript payload) { CScript opret; - - if (evalCodeInOpret != EVAL_TOKENS) { - std::cerr << "EncodeTokenOpRet() evalCode should be EVAL_TOKENS!" << std::endl; - return opret; // return empty - } + uint8_t tokenFuncId = 't'; + uint8_t evalCodeInOpret = EVAL_TOKENS; tokenid = revuint256(tokenid); @@ -93,6 +90,11 @@ CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 t return opret; } +// overload for compatibility +CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload) +{ + return EncodeTokenOpRet(tokenid, voutPubkeys, payload); +} uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector &origpubkey,std::string &name,std::string &description) { @@ -405,35 +407,59 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c std::cerr << "IsTokensvout() vopretExtra=" << HexStr(vopretExtra) << std::endl; //std::cerr << "IsTokensvout() vcontractOpret=" << HexStr(vcontractOpret) << std::endl;; - if (vopretExtra.size() < 2 /*|| vopretExtra.size() != vopretExtra.begin()[0]*/) { + uint8_t evalCodeInOpret; + if (vopretExtra.size() >= 2 /*|| vopretExtra.size() != vopretExtra.begin()[0] <-- shold we check this?*/) { std::cerr << "IsTokensvout() empty or incorrect contract opret" << std::endl; - return 0; + evalCodeInOpret = vopretExtra.begin()[1]; + } + else { + // if payload is empty maybe it is a claim to non-payload-one-token-eval vout? + evalCodeInOpret = EVAL_TOKENS; } - uint8_t evalCodeInOpret = vopretExtra.begin()[1]; - - if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { - CTxOut testVout; + // maybe this is dual-eval 1 pubkey or 1of2 pubkey vout? + if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { + CTxOut testDualVout; if (voutPubkeys.size() == 1) - testVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0]); + testDualVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0]); else // voutPubkeys.size() == 2 - testVout = MakeTokensCC1of2vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]); + testDualVout = 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; + if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) { + if(voutPubkeys.size() == 1) + std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout, eval2=" << evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + else + std::cerr << indentStr << "IsTokensvout() this is dual-eval token 1of2 vout or change, eval2=" << evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; return tx.vout[v].nValue; } } - // maybe it is token change? + // maybe this is claim to single-eval token? + if (voutPubkeys.size() == 1) { + CTxOut testTokenVout1; + testTokenVout1 = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]); + + if (tx.vout[v].scriptPubKey == testTokenVout1.scriptPubKey) { + std::cerr << indentStr << "IsTokensvout() this is single-eval token vout, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + return tx.vout[v].nValue; + } + } + + // maybe it is single-eval or dual-eval token change? std::vector vinPubkeys; ExtractTokensVinPubkeys(tx, vinPubkeys); for(std::vector::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) { - CTxOut testVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, *it); + CTxOut testTokenVout1 = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it); + CTxOut testDualVout1 = 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; + if (tx.vout[v].scriptPubKey == testTokenVout1.scriptPubKey) { + std::cerr << indentStr << "IsTokensvout() this is single-eval token change, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + return tx.vout[v].nValue; + } + + if (tx.vout[v].scriptPubKey == testDualVout1.scriptPubKey) { + std::cerr << indentStr << "IsTokensvout() this is dual-eval token change, vout eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; return tx.vout[v].nValue; } } diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index c87f8155d..a1f8adfd3 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -619,8 +619,9 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info * and also for setting spending plan for the funds' owner and heir * @return fundingtxid handle for subsequent references to this heir funding plan */ -template std::string HeirFund(uint64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) +template UniValue HeirFund(uint64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) { + UniValue result(UniValue::VOBJ); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); struct CCcontract_info *cp, C; @@ -664,24 +665,38 @@ template std::string HeirFund(uint64_t txfee, int64_t amount, voutTokenPubkeys.push_back(heirPubkey); // add change for txfee and opreturn vouts and sign tx: - return (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName))); + std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, + Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName)); + if (!rawhextx.empty()) { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hextx", rawhextx)); + } + else { + std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "sign error")); + } + } + else { // TODO: need result return unification with heiradd and claim + std::cerr << "HeirFund() could not find owner cc inputs" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "could not find owner cc inputs")); } - else // TODO: need result return unification with heiradd and claim - std::cerr << "HeirFund() could not find owner inputs" << std::endl; - } - else + else { std::cerr << "HeirFund() could not find normal inputs" << std::endl; - return std::string(""); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "could not find normal inputs")); + } + return result; } // if no these callers - it could not link -std::string HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){ +UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){ return HeirFund(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid); } -std::string HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) { +UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) { return HeirFund(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid); } @@ -735,8 +750,8 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */ - // add cryptocondition to spend this funded amount for either pk - mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); + // add cryptocondition to spend this funded amount for either pk + mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); if (inputs > amount) change = (inputs - amount); // -txfee <-- txfee pays user @@ -756,8 +771,16 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun))); - result.push_back(Pair("result", "success")); - result.push_back(Pair("hextx", rawhextx)); + if (!rawhextx.empty()) { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hextx", rawhextx)); + } + else { + std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "sign error")); + } + } else { std::cerr << "HeirAdd cannot find owner cc inputs" << std::endl; @@ -772,7 +795,7 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in } } else { - fprintf(stderr, "HeirAdd() can't find any heir CC funding tx's\n"); + fprintf(stderr, "HeirAdd can't find any heir CC funding tx's\n"); result.push_back(Pair("result", "error")); result.push_back(Pair("error", "can't find any heir CC funding transactions")); @@ -858,7 +881,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee }*/ // add vout with amount to claiming address - mtx.vout.push_back(Helper::makeClaimerVout(amount, myPubkey)); // vout[0] + mtx.vout.push_back(Helper::makeUserVout(amount, myPubkey)); // vout[0] // calc and add change vout: if (inputs > amount) diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 8f08a1588..e9710a471 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -43,9 +43,9 @@ public: 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) { +/* 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); @@ -64,20 +64,20 @@ 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_HEIR); + cpHeir = CCinit(&heirC, EVAL_TOKENS); return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs); } static CScript makeCreateOpRet(uint256 tokenid, std::vector voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) { - return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys, + return EncodeTokenOpRet(tokenid, voutTokenPubkeys, EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName)); } static CScript makeAddOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys, + return EncodeTokenOpRet(tokenid, voutTokenPubkeys, EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan)); } static CScript makeClaimOpRet(uint256 tokenid, std::vector voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) { - return EncodeTokenOpRet((uint8_t)'t', EVAL_TOKENS, tokenid, voutTokenPubkeys, + return EncodeTokenOpRet(tokenid, voutTokenPubkeys, EncodeHeirOpRet((uint8_t)'C', fundingtxid, isHeirSpendingBegan)); } @@ -85,11 +85,11 @@ public: return MakeTokensCC1of2vout(EVAL_HEIR, amount, ownerPubkey, heirPubkey); } static CTxOut makeUserVout(int64_t amount, CPubKey myPubkey) { - return MakeTokensCC1vout(EVAL_HEIR, amount, myPubkey); - } - static CTxOut makeClaimerVout(int64_t amount, CPubKey myPubkey) { - return MakeTokensCC1vout(EVAL_HEIR, amount, 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); @@ -477,7 +477,7 @@ public: CScript ownerScript; CScript heirScript; - if (m_checkNormals) { + 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; @@ -537,7 +537,7 @@ public: int64_t durationSec = CCduration(numblocks, m_latesttxid); // recreate scriptPubKey for heir and compare it with that of the vout: - if (vout.scriptPubKey == Helper::makeClaimerVout(vout.nValue, heirPubkey).scriptPubKey) { + 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"; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 847ddd921..82870c941 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -7454,13 +7454,13 @@ UniValue heirfund(const UniValue& params, bool fHelp) inactivitytime = atof((char*)params[4].get_str().c_str()); - hex = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, zeroid); - if (hex.size() > 0) { + result = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, zeroid); +/* if (hex.size() > 0) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); } else - ERR_RESULT("couldn't create heir fund"); + ERR_RESULT("couldn't create heir fund");*/ return result; } @@ -7573,13 +7573,13 @@ UniValue heirfundtokens(const UniValue& params, bool fHelp) assetid = Parseuint256((char*)params[5].get_str().c_str()); - hex = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, assetid); - if (hex.size() > 0) { + result = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, assetid); +/* if (hex.size() > 0) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); } else - ERR_RESULT("couldn't create heir fund"); + ERR_RESULT("couldn't create heir fund");*/ return result; From 9e7b0314666af5a18e3df54c7bb6604fc6ab7543 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 12:25:21 +0500 Subject: [PATCH 061/106] corr ccinit in HeirAdd --- src/cc/heir.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index a1f8adfd3..f3a3913a3 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -719,8 +719,8 @@ template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, in uint8_t funcId; uint8_t hasHeirSpendingBegun = 0; - //cp = CCinit(&C, Helper::getMyEval()); // for tokens shoud be EVAL_TOKENS to sign it correctly! - cp = CCinit(&C, EVAL_HEIR); // for tokens shoud be EVAL_TOKENS to sign it correctly! + cp = CCinit(&C, Helper::getMyEval()); // for tokens shoud be EVAL_TOKENS to sign it correctly! + //cp = CCinit(&C, EVAL_HEIR); // for tokens shoud be EVAL_TOKENS to sign it correctly! if (txfee == 0) txfee = 10000; From 46406f3c25e7649c20df82e5d7d5b1882025874b Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 13:06:06 +0500 Subject: [PATCH 062/106] corr CCinit in HeirClaim --- src/cc/CCtokens.cpp | 4 ++-- src/cc/heir.cpp | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index d1dcf0b1f..e54919155 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -427,9 +427,9 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) { if(voutPubkeys.size() == 1) - std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout, eval2=" << evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout, eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; else - std::cerr << indentStr << "IsTokensvout() this is dual-eval token 1of2 vout or change, eval2=" << evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() this is dual-eval token 1of2 vout or change, eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; return tx.vout[v].nValue; } } diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index f3a3913a3..8ee5d7e07 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -832,7 +832,8 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee std::string heirName; uint8_t hasHeirSpendingBegun = 0; - cp = CCinit(&C, Helper::getMyEval()); + //cp = CCinit(&C, Helper::getMyEval()); + cp = CCinit(&C, EVAL_HEIR); if (txfee == 0) txfee = 10000; @@ -919,8 +920,15 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid, (myPubkey == heirPubkey) ? 1 : hasHeirSpendingBegun)); // forward isHeirSpending to the next latest tx - result.push_back(Pair("result", "success")); - result.push_back(Pair("hextx", rawhextx)); + if (!rawhextx.empty()) { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hextx", rawhextx)); + } + else { + std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "sign error")); + } } else { fprintf(stderr, "HeirClaim() cant find Heir CC inputs\n"); From 395fac417354e3e62bed3787a98c303743bcd908 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 14:09:50 +0500 Subject: [PATCH 063/106] corr cp param to ...addr1of2set --- src/cc/heir.cpp | 2 +- src/cc/heir_validate.h | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 8ee5d7e07..9769f6f87 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -909,7 +909,7 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee Myprivkey(myprivkey); // set pubkeys for finding 1of2 cc in FinalizeCCtx to sign it: - Helper::CCaddrCoinsOrTokens1of2set(ownerPubkey, heirPubkey, coinaddr); + Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); // add 1of2 vout validation pubkeys (this is for tokens): std::vector voutTokenPubkeys; diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index e9710a471..2ad905808 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -51,10 +51,8 @@ public: cpHeir = CCinit(&heirC, EVAL_HEIR); return GetCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey); } - static void CCaddrCoinsOrTokens1of2set(CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { - struct CCcontract_info *cpHeir, heirC; - cpHeir = CCinit(&heirC, EVAL_HEIR); - CCaddr1of2set(cpHeir, ownerPubkey, heirPubkey, coinaddr); + static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { + CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr); } }; @@ -96,10 +94,9 @@ public: return GetTokensCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey); } - static void CCaddrCoinsOrTokens1of2set(CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { - struct CCcontract_info *cpHeir, heirC; - cpHeir = CCinit(&heirC, EVAL_HEIR); - CCaddrTokens1of2set(cpHeir, ownerPubkey, heirPubkey, coinaddr); + static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) { + + CCaddrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); } }; From 96a653004460b16c8850e065bff0699e2fa230b2 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 14:24:58 +0500 Subject: [PATCH 064/106] corr getting 1of2 addr in 1of2 validator --- src/cc/heir.cpp | 6 ++++-- src/cc/heir_validate.h | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 9769f6f87..9ec8729e3 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -902,10 +902,12 @@ template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners std::cerr << "HeirClaim() adding markeraddr=" << markeraddr << '\n'; */ - uint8_t myprivkey[32]; + // get address of 1of2 cond char coinaddr[64]; - // set priv key addresses in CC structure: Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); + + // retrieve priv key addresses for FinalizeCCtx: + uint8_t myprivkey[32]; Myprivkey(myprivkey); // set pubkeys for finding 1of2 cc in FinalizeCCtx to sign it: diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 2ad905808..f091e1381 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -419,7 +419,9 @@ public: char shouldBeAddr[65], ccAddr[65]; - GetCCaddress1of2(m_cp, shouldBeAddr, ownerPubkey, heirPubkey); + //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; From 2d8027854d1e1523145d796020e119e4df0d943e Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 16:22:14 +0500 Subject: [PATCH 065/106] first changes in assets for 2-eval vouts --- src/cc/CCassetsCore.cpp | 45 +++++++++++++---------------------------- src/cc/CCassetstx.cpp | 6 +++--- src/cc/CCinclude.h | 4 ++-- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 72404878d..09d0d8058 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -239,28 +239,23 @@ CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,st } */ -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey) +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey) { CScript opret; uint8_t evalcode = EVAL_ASSETS; - uint8_t funcId = (uint8_t)'t'; - uint8_t ccType = 0; - if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) - ccType = voutPubkeys.size(); - tokenid = revuint256(tokenid); switch ( assetFuncId ) { //case 't': this cannot be here case 'x': case 'o': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId); break; case 's': case 'b': case 'S': case 'B': - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId << price << origpubkey); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId << price << origpubkey); break; case 'E': case 'e': assetid2 = revuint256(assetid2); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcId << tokenid << ccType; if(ccType >= 1) ss << voutPubkeys[0]; if(ccType == 2) ss << voutPubkeys[1]; ss << assetFuncId << assetid2 << price << origpubkey); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << assetFuncId << assetid2 << price << origpubkey); break; default: fprintf(stderr,"EncodeAssetOpRet: illegal funcid.%02x\n", assetFuncId); @@ -270,7 +265,7 @@ CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, return(opret); } -// it is for compatibility, do not use this for new contracts (use DecodeTokenCreateOpRet) +/* it is for compatibility, do not use this for new contracts (use DecodeTokenCreateOpRet) bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description) { std::vector vopret; uint8_t evalcode,funcid,*script; @@ -282,9 +277,9 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &o return(true); } return(0); -} +} */ -uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey) +uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey) { std::vector vopretExtra; uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId; @@ -298,7 +293,6 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, // First - decode token opret: funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra); - /*GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); if (script == 0) { @@ -308,14 +302,14 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, //bool isEof = true; // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set! //bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof()); - if (funcId == 0 || vopretExtra.size() == 0) { + if (funcId == 0 || vopretExtra.size() < 2) { std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretExtra.size()=" << vopretExtra.size() << std::endl; return (uint8_t)0; } ////tokenid = revuint256(tokenid); already done in DecodeToken! - - assetFuncId = vopretExtra.begin()[0]; + evalCodeInOpret = vopretExtra.begin()[0]; + assetFuncId = vopretExtra.begin()[1]; //std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl; @@ -324,17 +318,6 @@ uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, //fprintf(stderr,"decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId); switch( assetFuncId ) { - /*case 'c': - return(funcid); - break; */ - /*case 't': - if (E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> tokenid; isEof = ss.eof()) || !isEof) - { - assetid = revuint256(assetid); - return(funcid); - } - break; */ - case 'x': case 'o': if (vopretExtra.size() == 1) // no data after 'assetFuncId' allowed { @@ -369,7 +352,7 @@ bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CT { uint256 assetid,assetid2; uint8_t evalCode; - if ( tx.vout.size() > 0 && DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey) != 0 ) + if ( tx.vout.size() > 0 && DecodeAssetTokenOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey) != 0 ) return(true); else return(false); @@ -382,7 +365,7 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,co uint8_t evalCode; n = tx.vout.size(); - if ( n == 0 || (funcid= DecodeAssetOpRet(tx.vout[n-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey)) == 0 ) + if ( n == 0 || (funcid= DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey)) == 0 ) return(false); if ( GetCCaddress(cp, CCaddr, pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG) != 0 ) return(true); @@ -432,7 +415,7 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr return(0); else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("invalid normal vout0 for buyvin"); - else if ((funcid = DecodeAssetOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' && vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'? + else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' && vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'? return eval->Invalid("invalid normal vout1 for buyvin"); else { @@ -470,7 +453,7 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr // this is just for log messages indentation fur debugging recursive calls: int32_t n = tx.vout.size(); - if ((funcid = DecodeAssetOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0) + if ((funcid = DecodeAssetTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0) { std::cerr << "ValidateAssetOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl; return(false); diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 3047876f4..1531f6893 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -93,7 +93,7 @@ UniValue AssetOrders(uint256 refassetid) { // for logging: funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey); //std::cerr << "addOrders() vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl; - if (vintx.vout.size() > 0 && (funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0) + if (vintx.vout.size() > 0 && (funcid = DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0) { if (refassetid != zero && assetid != refassetid) { @@ -486,7 +486,7 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) bidamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets - if( DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 'b') + if( DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 'b') mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b' (not 'B') // TODO: spend it also in FillBuyOffer? @@ -526,7 +526,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) askamount = vintx.vout[0].nValue; mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); - if (DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 's') + if (DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 's') mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s' (not 'S') // TODO: spend it also in FillSell? diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 14a500222..b90e4ff6f 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -159,8 +159,8 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); -bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); -uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); +//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); +uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, CScript payload); CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector voutPubkeys, CScript payload); From a7d7451c88da73a7da9e0da5473be99f5547c979 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 16:28:39 +0500 Subject: [PATCH 066/106] corr call to DecodeAssetTokenOpRet --- src/cc/assets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index ea44453ff..aab0a234f 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -150,7 +150,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti outputs = inputs = 0; preventCCvins = preventCCvouts = -1; - if((funcid = DecodeAssetOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 ) + if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 ) return eval->Invalid("AssetValidate: invalid opreturn payload"); // find token user cc addr From 41da2aed5f8d9071883c424730dd66ff089c163c Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 16:54:36 +0500 Subject: [PATCH 067/106] corr call to EncodeAssetOpRet --- src/cc/CCassetstx.cpp | 16 ++++++++-------- src/cc/CCinclude.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 1531f6893..2661b1f29 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -328,7 +328,7 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); std::vector voutTokenPubkeys; // should be empty - no token vouts - return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()))); + return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', zeroid, pricetotal, voutTokenPubkeys, Mypubkey()))); } CCerror = strprintf("no coins found to make buy offer"); return(""); @@ -380,7 +380,7 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(unspendablePubkey); - opret = EncodeAssetOpRet('s',assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); + opret = EncodeAssetOpRet('s', zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,opret)); } else { @@ -440,10 +440,10 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a std::vector voutTokenPubkeys; // should be empty - no token vouts if (assetid2 == zeroid) { - opret = EncodeAssetOpRet('s', assetid, zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); + opret = EncodeAssetOpRet('s', zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); } else { - opret = EncodeAssetOpRet('e', assetid, assetid2, pricetotal, voutTokenPubkeys, Mypubkey()); + opret = EncodeAssetOpRet('e', assetid2, pricetotal, voutTokenPubkeys, Mypubkey()); } return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret)); } @@ -495,7 +495,7 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) std::vector voutTokenPubkeys; // should be empty, no tokens vout - return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey()))); + return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', zeroid, 0, voutTokenPubkeys, Mypubkey()))); } } return(""); @@ -542,7 +542,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) GetCCaddress(cpAssets, myCCaddr, mypk); CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress - return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', assetid, zeroid, 0, voutTokenPubkeys, Mypubkey()))); + return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', zeroid, 0, voutTokenPubkeys, Mypubkey()))); } } return(""); @@ -620,7 +620,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(pubkey2pk(origpubkey)); - return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', assetid, zeroid, remaining_required, voutTokenPubkeys, origpubkey))); + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', zeroid, remaining_required, voutTokenPubkeys, origpubkey))); } else return("dont have any assets to fill bid"); } } @@ -722,7 +722,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(mypk); - return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid, assetid2, remaining_nValue, voutTokenPubkeys, origpubkey))); + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, voutTokenPubkeys, origpubkey))); } else { CCerror = strprintf("filltx not enough utxos"); fprintf(stderr,"%s\n", CCerror.c_str()); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index b90e4ff6f..170961340 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -158,7 +158,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, /*std::vector &origpubkey,*/ const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); //bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); From 4379cffe74a0f19c078d4af9a865a27fcba84389 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 17:01:42 +0500 Subject: [PATCH 068/106] corr call to EncodeAssetOpet in prices.cpp --- src/cc/prices.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index 9ba6d4a84..bda7248ea 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -328,7 +328,7 @@ std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingt // add addr2 std::vector voutTokenPubkeysEmpty; //TODO: add token vout pubkeys - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',bettoken,zeroid,0, voutTokenPubkeysEmpty, Mypubkey()))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',/*bettoken,*/zeroid,0, voutTokenPubkeysEmpty, Mypubkey()))); } else { From 8d8b253138bba7d1f5820b372bf56eab3a12a808 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 20:55:26 +0500 Subject: [PATCH 069/106] first time changed eval usage and MakeTokenCCcond.. for assets --- src/cc/CCassetsCore.cpp | 2 +- src/cc/CCassetstx.cpp | 114 ++++++++++++++++++++++++---------------- src/cc/CCinclude.h | 2 +- src/cc/CCtx.cpp | 2 +- src/cc/heir.cpp | 1 + src/cc/prices.cpp | 4 +- 6 files changed, 77 insertions(+), 48 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 09d0d8058..9bd17cef8 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -239,7 +239,7 @@ CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector origpubkey,st } */ -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey) +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector origpubkey) { CScript opret; uint8_t evalcode = EVAL_ASSETS; diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 2661b1f29..8dcde6e12 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -328,7 +328,9 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); std::vector voutTokenPubkeys; // should be empty - no token vouts - return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('b', zeroid, pricetotal, voutTokenPubkeys, Mypubkey()))); + return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee, + EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey())))); } CCerror = strprintf("no coins found to make buy offer"); return(""); @@ -342,7 +344,8 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p uint64_t mask; int64_t inputs, CCchange; CScript opret; - struct CCcontract_info *cpTokens,C; + struct CCcontract_info *cpAssets, assetsC; + struct CCcontract_info *cpTokens, tokensC; //std::cerr << "CreateSell() askamount=" << askamount << " pricetotal=" << pricetotal << std::endl; @@ -351,8 +354,8 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p return(""); } - cpTokens = CCinit(&C, EVAL_TOKENS); // NOTE: tokens is here - + cpAssets = CCinit(&assetsC, EVAL_ASSETS); // NOTE: this is for signing + if (txfee == 0) txfee = 10000; @@ -360,6 +363,8 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); + // add single-eval tokens: + cpTokens = CCinit(&tokensC, EVAL_TOKENS); // NOTE: tokens is here if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60)) > 0) { if (inputs < askamount) { @@ -369,19 +374,20 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p return (""); } - CPubKey unspendablePubkey = GetUnspendable(cpTokens, 0); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, unspendablePubkey)); + CPubKey unspendablePubkey = GetUnspendable(cpAssets, NULL); + mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, askamount, unspendablePubkey)); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker if (inputs > askamount) CCchange = (inputs - askamount); if (CCchange != 0) - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // change to single-eval token vout std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(unspendablePubkey); - opret = EncodeAssetOpRet('s', zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); - return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,opret)); + opret = EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey())); + return(FinalizeCCTx(mask,cpAssets, mtx, mypk, txfee, opret)); } else { fprintf(stderr, "need some tokens to place ask\n"); @@ -399,10 +405,10 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; uint64_t mask; int64_t inputs,CCchange; CScript opret; struct CCcontract_info *cp,C; - ////////////////////////////////////////// + ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// fprintf(stderr,"asset swaps disabled\n"); return(""); - ////////////////////////////////////////// + ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// if ( askamount < 0 || pricetotal < 0 ) { @@ -413,7 +419,7 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a if ( txfee == 0 ) txfee = 10000; - + ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// mypk = pubkey2pk(Mypubkey()); if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) @@ -421,13 +427,14 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a mask = ~((1LL << mtx.vin.size()) - 1); if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0) { + ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// if (inputs < askamount) { //was: askamount = inputs; std::cerr << "CreateSwap(): insufficient tokens for ask" << std::endl; CCerror = strprintf("insufficient tokens for ask"); return (""); } - + ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// CPubKey unspendablePubkey = GetUnspendable(cp, 0); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, askamount, unspendablePubkey)); @@ -436,15 +443,18 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a if (CCchange != 0) mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); - + ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// std::vector voutTokenPubkeys; // should be empty - no token vouts if (assetid2 == zeroid) { - opret = EncodeAssetOpRet('s', zeroid, pricetotal, voutTokenPubkeys, Mypubkey()); + opret = EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey())); } else { - opret = EncodeAssetOpRet('e', assetid2, pricetotal, voutTokenPubkeys, Mypubkey()); + opret = EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet('e', assetid2, pricetotal, Mypubkey())); } + ////////////////////////// NOT IMPLEMENTED YET///////////////////////////////// return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret)); } else { @@ -493,9 +503,11 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - std::vector voutTokenPubkeys; // should be empty, no tokens vout + std::vector voutTokenPubkeys; // should be empty, no token vouts - return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeAssetOpRet('o', zeroid, 0, voutTokenPubkeys, Mypubkey()))); + return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, + EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet('o', zeroid, 0, Mypubkey())))); } } return(""); @@ -505,13 +517,15 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CTransaction vintx; uint64_t mask; uint256 hashBlock; int64_t askamount; CPubKey mypk; - struct CCcontract_info *cpTokens,*cpAssets,C,assetsC; + CTransaction vintx; uint64_t mask; + uint256 hashBlock; + int64_t askamount; + CPubKey mypk; + struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC; uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector dummyOrigpubkey; - cpTokens = CCinit(&C, EVAL_TOKENS); - cpAssets = CCinit(&assetsC, EVAL_ASSETS); + cpTokens = CCinit(&tokensC, EVAL_TOKENS); if (txfee == 0) txfee = 10000; @@ -530,7 +544,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s' (not 'S') // TODO: spend it also in FillSell? - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); // one-eval token vout mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); std::vector voutTokenPubkeys; @@ -539,10 +553,15 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) char myCCaddr[65]; uint8_t myPrivkey[32]; Myprivkey(myPrivkey); + cpAssets = CCinit(&assetsC, EVAL_ASSETS); GetCCaddress(cpAssets, myCCaddr, mypk); - CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress - return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, EncodeAssetOpRet('x', zeroid, 0, voutTokenPubkeys, Mypubkey()))); + // this is only for unspendable addresses: + //CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress + + return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, + EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet('x', zeroid, 0, Mypubkey())))); } } return(""); @@ -568,7 +587,6 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f return(""); } cpTokens = CCinit(&tokensC, EVAL_TOKENS); - cpAssets = CCinit(&assetsC, EVAL_ASSETS); if (txfee == 0) txfee = 10000; @@ -598,21 +616,24 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f if (inputs > fillamount) CCchange = (inputs - fillamount); - CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); + //CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); uint8_t unspendableAssetsPrivkey[32]; + cpTokens = CCinit(&assetsC, EVAL_ASSETS); CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // 0 coins remainder - mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // 1 coins to normal - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // 2 tokens paid + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder + mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens paid if (CCchange != 0) - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // 3 change in tokens + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout3 change in single-eval tokens - fprintf(stderr,"remaining %llu -> origpubkey\n", (long long)remaining_required); + fprintf(stderr,"FillBuyOffer remaining %llu -> origpubkey\n", (long long)remaining_required); char unspendableAssetsAddr[64]; + cpAssets = CCinit(&assetsC, EVAL_ASSETS); GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); + // add additional unspendable addr from Assets: CCaddr2set(cpTokens, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); @@ -620,7 +641,9 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(pubkey2pk(origpubkey)); - return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, EncodeAssetOpRet('B', zeroid, remaining_required, voutTokenPubkeys, origpubkey))); + return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee, + EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey)))); } else return("dont have any assets to fill bid"); } } @@ -637,10 +660,10 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt CPubKey mypk; std::vector origpubkey; double dprice; - uint64_t mask; - int32_t askvout=0; + uint64_t mask = 0; + int32_t askvout = 0; int64_t received_assetoshis, total_nValue, orig_assetoshis, paid_nValue, remaining_nValue, inputs, CCchange=0; - struct CCcontract_info *cpTokens, tokensC; + //struct CCcontract_info *cpTokens, tokensC; struct CCcontract_info *cpAssets, assetsC; if (fillunits < 0) @@ -656,8 +679,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt return(""); } - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - cpAssets = CCinit(&assetsC, EVAL_ASSETS); + cpAssets = CCinit(&assetsC, EVAL_ASSETS); if (txfee == 0) txfee = 10000; @@ -676,7 +698,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx! if (assetid2 != zeroid) - inputs = AddAssetInputs(cpTokens, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet + inputs = AddAssetInputs(cpAssets, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet else { inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60); @@ -698,14 +720,15 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt if (assetid2 != zeroid && inputs > paid_nValue) CCchange = (inputs - paid_nValue); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, orig_assetoshis - received_assetoshis, GetUnspendable(cpTokens, NULL))); // vout.0 tokens cc addr - ask remainder - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //vout.1 tokens to self + mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // vout.0 tokens cc addr - ask remainder + mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, received_assetoshis, mypk)); //vout.1 tokens to self // NOTE: no marker here if (assetid2 != zeroid) { std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl; - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //vout.2 tokens... (swap is not implemented yet) + // TODO: change MakeCC1vout appropriately when implementing: + //mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //vout.2 tokens... (swap is not implemented yet) } else { //std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl; @@ -715,14 +738,17 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt // not implemented if (CCchange != 0) { std::cerr << "FillSell() WARNING: asset swap not implemented yet! (CCchange)" << std::endl; - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr + // TODO: change MakeCC1vout appropriately when implementing: + //mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr (swap not implemented) } // vout verification pubkeys: std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(mypk); - return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, voutTokenPubkeys, origpubkey))); + return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, + EncodeTokenOpRet(assetid, voutTokenPubkeys, + EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, origpubkey)))); } else { CCerror = strprintf("filltx not enough utxos"); fprintf(stderr,"%s\n", CCerror.c_str()); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 170961340..03af2f92d 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -158,7 +158,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, /*std::vector &origpubkey,*/ const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector vinPubkeys); bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); -CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector voutPubkeys, std::vector origpubkey); +CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector origpubkey); //bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 29e1fe0ab..630f37dca 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -65,7 +65,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran GetCCaddress(cp,myaddr,mypk); mycond = MakeCCcond1(cp->evalcode,mypk); - GetTokensCCaddress(cp, myaddr, mypk); + GetTokensCCaddress(cp, mytokensaddr, mypk); mytokenscond = MakeTokensCCcond1(cp->evalcode, mypk); unspendablepk = GetUnspendable(cp,unspendablepriv); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 9ec8729e3..48dc543ab 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -646,6 +646,7 @@ template UniValue HeirFund(uint64_t txfee, int64_t amount, std mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey)); // add a marker for finding all plans in HeirList() + // TODO: change marker either to cc or normal txidaddr unspendable CPubKey heirUnspendablePubKey = GetUnspendable(cp, 0); mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(heirUnspendablePubKey)) << OP_CHECKSIG)); // TODO: do we need this marker? diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index bda7248ea..369495b1a 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -328,7 +328,9 @@ std::string PricesAddFunding(uint64_t txfee,uint256 refbettoken,uint256 fundingt // add addr2 std::vector voutTokenPubkeysEmpty; //TODO: add token vout pubkeys - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',/*bettoken,*/zeroid,0, voutTokenPubkeysEmpty, Mypubkey()))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee, + EncodeTokenOpRet(bettoken, voutTokenPubkeysEmpty, + EncodeAssetOpRet('t',/*bettoken,*/zeroid, 0, Mypubkey())))); } else { From ffba12b55b211edbececc3016e96a81d6c6ea5c2 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 21:17:51 +0500 Subject: [PATCH 070/106] added single-eval token cond to FinalizeCCtx --- src/cc/CCtx.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 630f37dca..7640b35bb 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -43,10 +43,12 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; - int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64],mytokensaddr[64]; - uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; - CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL; + int32_t i,utxovout,n,err = 0; + char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64]; + uint8_t *privkey, myprivkey[32], unspendablepriv[32], *msg32 = 0; + CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL; CPubKey unspendablepk; + struct CCcontract_info *cpTokens, tokensC; n = mtx.vout.size(); for (i=0; ievalcode, mypk); + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + GetCCaddress(cpTokens, mysingletokensaddr, mypk); + mysingletokenscond = MakeCCcond1(cpTokens->evalcode, mypk); + unspendablepk = GetUnspendable(cp,unspendablepriv); GetCCaddress(cp,unspendable,unspendablepk); othercond = MakeCCcond1(cp->evalcode,unspendablepk); @@ -149,6 +155,12 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran cond = mytokenscond; fprintf(stderr,"FinalizeCCTx() matched TokensCC1vout CC addr.(%s)\n",mytokensaddr); } + else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout + { + privkey = myprivkey; + cond = mysingletokenscond; + fprintf(stderr, "FinalizeCCTx() matched single-eval TokensCC1vout CC addr.(%s)\n", mytokensaddr); + } else if ( strcmp(destaddr,unspendable) == 0 ) { privkey = unspendablepriv; From 114d7779d6402403971ec04e056f3263c4b0a1ae Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 23:23:49 +0500 Subject: [PATCH 071/106] added support for 2 check pubkeys in IsTokenVout --- src/cc/CCtokens.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index e54919155..7296beaf2 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -420,18 +420,28 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // maybe this is dual-eval 1 pubkey or 1of2 pubkey vout? if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { CTxOut testDualVout; - if (voutPubkeys.size() == 1) - testDualVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0]); - else // voutPubkeys.size() == 2 - testDualVout = MakeTokensCC1of2vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]); - + // check dual-eval 1 pubkey vout with the first pubkey + testDualVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0]); if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) { - if(voutPubkeys.size() == 1) - std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout, eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; - else - std::cerr << indentStr << "IsTokensvout() this is dual-eval token 1of2 vout or change, eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() this is one-eval token vout (i=0), eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; return tx.vout[v].nValue; } + + if(voutPubkeys.size() == 2) { + // check dual eval 1of2 pubkeys vout + testDualVout = MakeTokensCC1of2vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]); + if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) { + std::cerr << indentStr << "IsTokensvout() this is dual-eval token 1of2 vout, eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + return tx.vout[v].nValue; + } + + // check dual eval 1 pubkey vout with the second pubkey + testDualVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[1]); + if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) { + std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout (i=1), eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + return tx.vout[v].nValue; + } + } } // maybe this is claim to single-eval token? From c66787ada63fee0274dcf14510f13faae4f65388 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 23:39:04 +0500 Subject: [PATCH 072/106] added support for 2 check pubkeys for single-eval token vouts --- src/cc/CCtokens.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 7296beaf2..5d25bdbaa 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -442,17 +442,23 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c return tx.vout[v].nValue; } } - } + - // maybe this is claim to single-eval token? - if (voutPubkeys.size() == 1) { + // maybe this is claim to single-eval token? CTxOut testTokenVout1; testTokenVout1 = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]); - if (tx.vout[v].scriptPubKey == testTokenVout1.scriptPubKey) { - std::cerr << indentStr << "IsTokensvout() this is single-eval token vout, returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() this is single-eval token vout (i=0), returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; return tx.vout[v].nValue; } + + if (voutPubkeys.size() == 2) { + testTokenVout1 = MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]); + if (tx.vout[v].scriptPubKey == testTokenVout1.scriptPubKey) { + std::cerr << indentStr << "IsTokensvout() this is single-eval token vout (i=1), returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + return tx.vout[v].nValue; + } + } } // maybe it is single-eval or dual-eval token change? From dddda4e32b7132f5354fd3e69788883ed05ef4c7 Mon Sep 17 00:00:00 2001 From: dimxy Date: Tue, 15 Jan 2019 23:44:13 +0500 Subject: [PATCH 073/106] corr logging in IsTokensVout --- src/cc/CCtokens.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 5d25bdbaa..48172971f 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -423,7 +423,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c // check dual-eval 1 pubkey vout with the first pubkey testDualVout = MakeTokensCC1vout(evalCodeInOpret, tx.vout[v].nValue, voutPubkeys[0]); if (tx.vout[v].scriptPubKey == testDualVout.scriptPubKey) { - std::cerr << indentStr << "IsTokensvout() this is one-eval token vout (i=0), eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; + std::cerr << indentStr << "IsTokensvout() this is dual-eval token vout (i=0), eval2=" << (int)evalCodeInOpret << ", returning nValue=" << tx.vout[v].nValue << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl; return tx.vout[v].nValue; } From ee848abde90130b90823e90e9b2e666d26748469 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 11:45:21 +0500 Subject: [PATCH 074/106] corr mysingletokenscond in FinalizeCCtx (corr err message in rpc call) --- src/cc/CCtx.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 7640b35bb..e3688b3bf 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -72,7 +72,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran cpTokens = CCinit(&tokensC, EVAL_TOKENS); GetCCaddress(cpTokens, mysingletokensaddr, mypk); - mysingletokenscond = MakeCCcond1(cpTokens->evalcode, mypk); + mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk); unspendablepk = GetUnspendable(cp,unspendablepriv); GetCCaddress(cp,unspendable,unspendablepk); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 82870c941..6bc267e0f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -7346,7 +7346,7 @@ UniValue tokenfillask(const UniValue& params, bool fHelp) result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); } else { - ERR_RESULT("couldnt fill bid"); + ERR_RESULT("couldnt fill ask"); } } else { ERR_RESULT("fillunits must be positive"); From a7833f272f420041f6fe2b331798410f6a9b23c8 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 12:12:41 +0500 Subject: [PATCH 075/106] added othertokenscond to FinalizeCCtx --- src/cc/CCassetstx.cpp | 11 ++++++++++- src/cc/CCtx.cpp | 21 +++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 8dcde6e12..69a1b0c6f 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -618,7 +618,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f //CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); uint8_t unspendableAssetsPrivkey[32]; - cpTokens = CCinit(&assetsC, EVAL_ASSETS); + cpTokens = CCinit(&assetsC, EVAL_ASSETS); //??? CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder @@ -742,6 +742,15 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt //mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr (swap not implemented) } + uint8_t unspendableAssetsPrivkey[32]; + char unspendableAssetsAddr[64]; + // init 'unspenable' privkey and pubkey + CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); + GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); + + // add additional unspendable addr from Assets: + CCaddr2set(cpAssets, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); + // vout verification pubkeys: std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(mypk); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index e3688b3bf..46395815e 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -44,9 +44,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; int32_t i,utxovout,n,err = 0; - char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64]; + char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], tokensunspendable[64]; uint8_t *privkey, myprivkey[32], unspendablepriv[32], *msg32 = 0; - CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL; + CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL; CPubKey unspendablepk; struct CCcontract_info *cpTokens, tokensC; @@ -74,9 +74,12 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran GetCCaddress(cpTokens, mysingletokensaddr, mypk); mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk); - unspendablepk = GetUnspendable(cp,unspendablepriv); - GetCCaddress(cp,unspendable,unspendablepk); - othercond = MakeCCcond1(cp->evalcode,unspendablepk); + unspendablepk = GetUnspendable(cp, unspendablepriv); + GetCCaddress(cp, unspendable, unspendablepk); + othercond = MakeCCcond1(cp->evalcode, unspendablepk); + + GetTokensCCaddress(cp, tokensunspendable, unspendablepk); + othertokenscond = MakeTokensCCcond1(cp->evalcode, unspendablepk); //Reorder vins so that for multiple normal vins all other except vin0 goes to the end //This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation. @@ -165,8 +168,14 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = unspendablepriv; cond = othercond; - //fprintf(stderr,"FinalizeCCTx() unspendable CC addr.(%s)\n",unspendable); + //fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable); } + else if (strcmp(destaddr, tokensunspendable) == 0) + { + privkey = unspendablepriv; + cond = othertokenscond; + fprintf(stderr,"FinalizeCCTx() matched tokensunspendable CC addr.(%s)\n",unspendable); + } // check if this is the 2nd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr2) == 0) { From 406fc539257e26d65206a66111538f189fc613a5 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 12:17:35 +0500 Subject: [PATCH 076/106] removed extra CCaddr2set --- src/cc/CCassetstx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 69a1b0c6f..fc026d158 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -742,14 +742,14 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt //mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr (swap not implemented) } - uint8_t unspendableAssetsPrivkey[32]; + /* uint8_t unspendableAssetsPrivkey[32]; char unspendableAssetsAddr[64]; // init 'unspenable' privkey and pubkey CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); // add additional unspendable addr from Assets: - CCaddr2set(cpAssets, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); + CCaddr2set(cpAssets, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);*/ // vout verification pubkeys: std::vector voutTokenPubkeys; From 4903298fc311fcacdca6f728e09a63ff21c8c013 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 14:11:29 +0500 Subject: [PATCH 077/106] corr tokesnunspenable priv and pk --- src/cc/CCtx.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 46395815e..56cc8a9ef 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -45,9 +45,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; int32_t i,utxovout,n,err = 0; char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], tokensunspendable[64]; - uint8_t *privkey, myprivkey[32], unspendablepriv[32], *msg32 = 0; + uint8_t *privkey, myprivkey[32], unspendablepriv[32], tokensunspendablepriv[32], *msg32 = 0; CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL; - CPubKey unspendablepk; + CPubKey unspendablepk, tokensunspendablepk; struct CCcontract_info *cpTokens, tokensC; n = mtx.vout.size(); @@ -78,8 +78,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran GetCCaddress(cp, unspendable, unspendablepk); othercond = MakeCCcond1(cp->evalcode, unspendablepk); - GetTokensCCaddress(cp, tokensunspendable, unspendablepk); - othertokenscond = MakeTokensCCcond1(cp->evalcode, unspendablepk); + tokensunspendablepk = GetUnspendable(cpTokens, tokensunspendablepriv); + GetTokensCCaddress(cp, tokensunspendable, tokensunspendablepk); + othertokenscond = MakeTokensCCcond1(cp->evalcode, tokensunspendablepk); //Reorder vins so that for multiple normal vins all other except vin0 goes to the end //This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation. From a16e80dac45cfbcc7df7b1ed8f8458dba9d1dbaa Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 14:22:23 +0500 Subject: [PATCH 078/106] more corr in tokensunspendable --- src/cc/CCtx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 56cc8a9ef..0463bf7c3 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -79,7 +79,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran othercond = MakeCCcond1(cp->evalcode, unspendablepk); tokensunspendablepk = GetUnspendable(cpTokens, tokensunspendablepriv); - GetTokensCCaddress(cp, tokensunspendable, tokensunspendablepk); + GetCCaddress(cpTokens, tokensunspendable, tokensunspendablepk); othertokenscond = MakeTokensCCcond1(cp->evalcode, tokensunspendablepk); //Reorder vins so that for multiple normal vins all other except vin0 goes to the end From f67a849be0bfdb7f78116ab74f96a81ae016e1ba Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 14:27:45 +0500 Subject: [PATCH 079/106] corr CCaddr2set for tokens support in FillSell --- src/cc/CCassetstx.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index fc026d158..39a58146b 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -742,14 +742,14 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt //mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, CCchange, mypk)); //vout.3 coins in Assets cc addr (swap not implemented) } - /* uint8_t unspendableAssetsPrivkey[32]; + uint8_t unspendableAssetsPrivkey[32]; char unspendableAssetsAddr[64]; // init 'unspenable' privkey and pubkey CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); - // add additional unspendable addr from Assets: - CCaddr2set(cpAssets, EVAL_ASSETS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);*/ + // add additional dual-eval (assets+tokens) unspendable assets address's privkey: + CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); // vout verification pubkeys: std::vector voutTokenPubkeys; From 457b9aff54e581c4aaa24c305f37b535885dafec Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 14:41:39 +0500 Subject: [PATCH 080/106] more corr othertokenscond, set cp->unspendable --- src/cc/CCtx.cpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 0463bf7c3..2959ba7d7 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -47,7 +47,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], tokensunspendable[64]; uint8_t *privkey, myprivkey[32], unspendablepriv[32], tokensunspendablepriv[32], *msg32 = 0; CC *mycond=0, *othercond=0, *othercond2=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL; - CPubKey unspendablepk, tokensunspendablepk; + CPubKey unspendablepk /*, tokensunspendablepk*/; struct CCcontract_info *cpTokens, tokensC; n = mtx.vout.size(); @@ -66,21 +66,27 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran GetCCaddress(cp,myaddr,mypk); mycond = MakeCCcond1(cp->evalcode,mypk); - + + // to spend from single-eval evalcode 'unspendable' + unspendablepk = GetUnspendable(cp, unspendablepriv); + GetCCaddress(cp, unspendable, unspendablepk); + othercond = MakeCCcond1(cp->evalcode, unspendablepk); + + // tokens support: + + // to spend from dual-eval mypk vout GetTokensCCaddress(cp, mytokensaddr, mypk); mytokenscond = MakeTokensCCcond1(cp->evalcode, mypk); + // to spend from single-eval EVAL_TOKENS mypk cpTokens = CCinit(&tokensC, EVAL_TOKENS); GetCCaddress(cpTokens, mysingletokensaddr, mypk); mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk); - unspendablepk = GetUnspendable(cp, unspendablepriv); - GetCCaddress(cp, unspendable, unspendablepk); - othercond = MakeCCcond1(cp->evalcode, unspendablepk); - - tokensunspendablepk = GetUnspendable(cpTokens, tokensunspendablepriv); - GetCCaddress(cpTokens, tokensunspendable, tokensunspendablepk); - othertokenscond = MakeTokensCCcond1(cp->evalcode, tokensunspendablepk); + // to spend from dual-eval EVAL_TOKEN+evalcode 'unspendable' pk + //tokensunspendablepk = GetUnspendable(cpTokens, tokensunspendablepriv); + GetTokensCCaddress(cp, tokensunspendable, unspendablepk); + othertokenscond = MakeTokensCCcond1(cp->evalcode, unspendablepk); //Reorder vins so that for multiple normal vins all other except vin0 goes to the end //This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation. @@ -147,7 +153,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey); //fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); - std::cerr << "FinalizeCCtx() destaddr=" << destaddr << " myaddr=" << myaddr << std::endl; + std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " myaddr=" << myaddr << std::endl; if( strcmp(destaddr,myaddr) == 0 ) { privkey = myprivkey; From 029d3af05aefdc04d8862ef8ea81afb0f1431638 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 15:16:30 +0500 Subject: [PATCH 081/106] add logging origpubkey to FillSell --- src/cc/CCassetstx.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 39a58146b..5b21fc1b1 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -652,7 +652,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f // send coins, receive tokens -std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 asktxid,int64_t fillunits) +std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 asktxid, int64_t fillunits) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CTransaction vintx,filltx; @@ -685,7 +685,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt txfee = 10000; mypk = pubkey2pk(Mypubkey()); - if (AddNormalinputs(mtx,mypk,txfee,3) > 0) + if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) { mask = ~((1LL << mtx.vin.size()) - 1); if (GetTransaction(asktxid, vintx, hashBlock, false) != 0) @@ -731,7 +731,7 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt //mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, paid_nValue, origpubkey)); //vout.2 tokens... (swap is not implemented yet) } else { - //std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl; + std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl; mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins normal to whom who asked token } From b807d8eb29b8a0eb2b74e3bc2e32ba3456193c8e Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 15:29:39 +0500 Subject: [PATCH 082/106] corr dummy evalcode in DecodeAssetTokenOpRet --- src/cc/CCassetsCore.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 9bd17cef8..09806a96c 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -325,14 +325,14 @@ uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOp } break; case 's': case 'b': case 'S': case 'B': - if (E_UNMARSHAL(vopretExtra, ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0) + if (E_UNMARSHAL(vopretExtra, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0) { //fprintf(stderr,"got price %llu\n",(long long)price); return(assetFuncId); } break; case 'E': case 'e': - if ( E_UNMARSHAL(vopretExtra, ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) + if ( E_UNMARSHAL(vopretExtra, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) { //fprintf(stderr,"got price %llu\n",(long long)price); assetid2 = revuint256(assetid2); From 830b54cf20fa8bd68436129a9128a2ed4079bff6 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 17:45:32 +0500 Subject: [PATCH 083/106] corr unmarshal vopretStripped --- src/cc/CCassetsCore.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 09806a96c..a7ca074db 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -281,7 +281,7 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector &o uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector &origpubkey) { - std::vector vopretExtra; + std::vector vopretExtra, vopretStripped; uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId; uint256 dummyTokenid; std::vector voutPubkeysDummy; @@ -307,9 +307,14 @@ uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOp return (uint8_t)0; } + if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size + std::cerr << "DecodeAssetTokenOpRet() could not unmarshal vopretStripped" << std::endl; + return (uint8_t)0; + } + ////tokenid = revuint256(tokenid); already done in DecodeToken! - evalCodeInOpret = vopretExtra.begin()[0]; - assetFuncId = vopretExtra.begin()[1]; + evalCodeInOpret = vopretStripped.begin()[0]; + assetFuncId = vopretStripped.begin()[1]; //std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl; @@ -319,7 +324,7 @@ uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOp switch( assetFuncId ) { case 'x': case 'o': - if (vopretExtra.size() == 1) // no data after 'assetFuncId' allowed + if (vopretExtra.size() == 2) // no data after 'evalcode assetFuncId' allowed { return(assetFuncId); } @@ -327,20 +332,20 @@ uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOp case 's': case 'b': case 'S': case 'B': if (E_UNMARSHAL(vopretExtra, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0) { - //fprintf(stderr,"got price %llu\n",(long long)price); + //fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price); return(assetFuncId); } break; case 'E': case 'e': if ( E_UNMARSHAL(vopretExtra, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) { - //fprintf(stderr,"got price %llu\n",(long long)price); + //fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price); assetid2 = revuint256(assetid2); return(assetFuncId); } break; default: - fprintf(stderr,"DecodeAssetOpRet: illegal assetFuncId.%02x\n", assetFuncId); + fprintf(stderr,"DecodeAssetTokenOpRet: illegal assetFuncId.%02x\n", assetFuncId); //funcId = 0; break; } From dae431eaa52a4ca76024c3f35d8ede098d20a24d Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 17:58:46 +0500 Subject: [PATCH 084/106] corr vopretStripped use in DecodeAssetsTokenOpret --- src/cc/CCassetsCore.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index a7ca074db..7084b1483 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -324,20 +324,20 @@ uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOp switch( assetFuncId ) { case 'x': case 'o': - if (vopretExtra.size() == 2) // no data after 'evalcode assetFuncId' allowed + if (vopretStripped.size() == 2) // no data after 'evalcode assetFuncId' allowed { return(assetFuncId); } break; case 's': case 'b': case 'S': case 'B': - if (E_UNMARSHAL(vopretExtra, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0) + if (E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0) { //fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price); return(assetFuncId); } break; case 'E': case 'e': - if ( E_UNMARSHAL(vopretExtra, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) + if ( E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 ) { //fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price); assetid2 = revuint256(assetid2); From e23073fff52725a941a4bd6da8c71a57fd968353 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Wed, 16 Jan 2019 14:05:54 +0100 Subject: [PATCH 085/106] Channels adaptation to TokensCC (#3) * Initial changes * ChannelsCC adaptation * Fix * Fix * Fix * Fix * Fix * Fix * Fix * Fix * Fix * Fix --- src/cc/CCchannels.h | 2 +- src/cc/CCinclude.h | 3 + src/cc/CCtokens.cpp | 8 +- src/cc/channels.cpp | 353 ++++++++++++++++++++++----------------- src/wallet/rpcwallet.cpp | 15 +- 5 files changed, 217 insertions(+), 164 deletions(-) diff --git a/src/cc/CCchannels.h b/src/cc/CCchannels.h index 49b4a7adf..10cb4d224 100644 --- a/src/cc/CCchannels.h +++ b/src/cc/CCchannels.h @@ -21,7 +21,7 @@ #define CHANNELS_MAXPAYMENTS 1000 bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); -std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment); +std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 tokenid); std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret); std::string ChannelClose(uint64_t txfee,uint256 opentxid); std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 03af2f92d..d134d9037 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -59,6 +59,9 @@ extern std::string CCerror; #define CC_MAXVINS 1024 #define SMALLVAL 0.000000000000001 +#define SATOSHIDEN ((uint64_t)100000000L) +#define dstr(x) ((double)(x) / SATOSHIDEN) + #ifndef _BITS256 #define _BITS256 union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index 48172971f..57aeb4369 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -714,10 +714,10 @@ int64_t GetTokenBalance(CPubKey pk, uint256 tokenid) CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CTransaction tokentx; - CCerror = strprintf("obsolete, cannot return correct value without eval"); - return 0; + // CCerror = strprintf("obsolete, cannot return correct value without eval"); + // return 0; -/* if (GetTransaction(tokenid, tokentx, hashBlock, false) == 0) + if (GetTransaction(tokenid, tokentx, hashBlock, false) == 0) { fprintf(stderr, "cant find tokenid\n"); CCerror = strprintf("cant find tokenid"); @@ -726,7 +726,7 @@ int64_t GetTokenBalance(CPubKey pk, uint256 tokenid) struct CCcontract_info *cp, C; cp = CCinit(&C, EVAL_TOKENS); - return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0)); */ + return(AddTokenCCInputs(cp, mtx, pk, tokenid, 0, 0)); } UniValue TokenInfo(uint256 tokenid) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index d516d0144..2a7ebc931 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -64,15 +64,16 @@ Possible third iteration: int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub, CPubKey destpub,int32_t v) { - char destaddr[65],channeladdr[65]; + char destaddr[65],channeladdr[65],tokenschanneladdr[65]; GetCCaddress1of2(cp,channeladdr,srcpub,destpub); + GetTokensCCaddress1of2(cp,tokenschanneladdr,srcpub,destpub); if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,channeladdr) == 0 ) + if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && (strcmp(destaddr,channeladdr) == 0 || strcmp(destaddr,tokenschanneladdr) == 0)) return(tx.vout[v].nValue); } - return(0); + return(0); } int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey pubkey,int32_t v) @@ -88,17 +89,31 @@ int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,C return(0); } -CScript EncodeChannelsOpRet(uint8_t funcid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) +CScript EncodeChannelsOpRet(uint8_t funcid,uint256 tokenid,uint256 opentxid,CPubKey srcpub,CPubKey destpub,int32_t numpayments,int64_t payment,uint256 hashchain) { CScript opret; uint8_t evalcode = EVAL_CHANNELS; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << opentxid << srcpub << destpub << numpayments << payment << hashchain); + if (tokenid!=zeroid) + { + std::vector pks; + pks.push_back(srcpub); + pks.push_back(destpub); + return(EncodeTokenOpRet(tokenid,pks,opret)); + } return(opret); } -uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) +uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey, uint256 &tokenid, uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain) { - std::vector vopret; uint8_t *script,e,f; - GetOpReturnData(scriptPubKey, vopret); + std::vector vopret; uint8_t *script,e,f,tokenevalcode; + std::vector pubkeys; std::vector vOpretExtra; + + if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0) + { + if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0); + } + else GetOpReturnData(scriptPubKey, vopret); if ( vopret.size() > 2 ) { script = (uint8_t *)vopret.data(); @@ -115,46 +130,56 @@ uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey,uint256 &opentxid, CPubK bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) { - static uint256 zerohash; - uint256 txid,param3; + uint256 txid,param3,tokenid; CPubKey srcpub,destpub; - int32_t param1; int64_t param2; uint8_t funcid; - CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis; - numvins = tx.vin.size(); - numvouts = tx.vout.size(); + int32_t param1,numvouts; int64_t param2; uint8_t funcid; + CTransaction vinTx; uint256 hashBlock; int64_t inputs=0,outputs=0; - if ((numvouts=tx.vout.size()) > 0 && DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3)!=0) - { - for (i=0; i 0 && (funcid=DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, param1, param2, param3))!=0) + { + switch (funcid) { - if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); - else - { - inputs += vinTx.vout[tx.vin[i].prevout.n].nValue; - } + case 'O': + return (true); + case 'P': + if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("cant find vinTx"); + inputs = vinTx.vout[tx.vin[1].prevout.n].nValue; + outputs = tx.vout[0].nValue + tx.vout[3].nValue; + break; + case 'C': + if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("cant find vinTx"); + inputs = vinTx.vout[tx.vin[1].prevout.n].nValue; + outputs = tx.vout[0].nValue; + break; + case 'R': + if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("cant find vinTx"); + inputs = vinTx.vout[tx.vin[1].prevout.n].nValue; + outputs = tx.vout[2].nValue; + break; + default: + return (false); } + if ( inputs != outputs ) + { + fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); + return eval->Invalid("mismatched inputs != outputs"); + } + else return (true); } else { return eval->Invalid("invalid op_return data"); } - for (i=0; iInvalid("mismatched inputs != outputs + txfee"); - } - else return(true); + return(false); } bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) { int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,p1,param1; bool retval; - uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain; + uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain,tokenid; uint8_t funcid,hash[32],hashdest[32]; int64_t p2,param2,payment; CPubKey srcpub, destpub; @@ -169,15 +194,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { if (ChannelsExactAmounts(cp,eval,tx,1,10000) == false ) { - fprintf(stderr,"Channelsget invalid amount\n"); - return false; + return eval->Invalid("invalid channel inputs vs. outputs!"); } else { txid = tx.GetHash(); memcpy(hash,&txid,sizeof(hash)); - - if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, opentxid, srcpub, destpub, param1, param2, param3)) != 0) + if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, tokenid, opentxid, srcpub, destpub, param1, param2, param3)) != 0) { switch ( funcid ) { @@ -213,9 +236,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)!"); else if ( IsChannelsMarkervout(cp,tx,destpub,2)==0 ) return eval->Invalid("vout.2 is CC for channelPayment (marker to dstPub)!"); - else if ( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) + else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.3 is CC for channelPayment!"); + else if ( tokenid==zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) return eval->Invalid("vout.3 is normal for channelPayment!"); - else if ( tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) + else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[3].nValue,destpub).scriptPubKey) + return eval->Invalid("payment funds do not go to receiver!"); + else if ( tokenid==zeroid && tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG) return eval->Invalid("payment funds do not go to receiver!"); else if ( param1 > CHANNELS_MAXPAYMENTS) return eval->Invalid("too many payment increments!"); @@ -223,7 +250,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0) { - if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') + if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O') return eval->Invalid("invalid channelopen OP_RETURN data!"); endiancpy(hash, (uint8_t * ) & param3, 32); for (i = 0; i < numpayments-param1; i++) @@ -239,7 +266,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & } if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { - if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) + if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) return eval->Invalid("invalid destination for sender marker!"); @@ -279,13 +306,13 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("too many payment increments!"); else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) return eval->Invalid("invalid open txid!"); - else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') + else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') return eval->Invalid("invalid channelopen OP_RETURN data!"); else if (tx.vout[0].nValue != param1*payment) return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { - if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) + if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey) return eval->Invalid("invalid destination for sender marker!"); @@ -318,19 +345,23 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vout.0 is CC for channelRefund (marker to srcPub)!"); else if ( IsChannelsMarkervout(cp,tx,destpub,1)==0 ) return eval->Invalid("vout.1 is CC for channelRefund (marker to dstPub)!"); - else if ( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) - return eval->Invalid("vout.2 is normal for channelRefund!"); - else if ( tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG) + else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.2 is CC for channelPayment!"); + else if ( tokenid==zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) + return eval->Invalid("vout.2 is normal for channelPayment!"); + else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[2].nValue,srcpub).scriptPubKey) + return eval->Invalid("payment funds do not go to sender!"); + else if ( tokenid==zeroid && tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG) return eval->Invalid("payment funds do not go to sender!"); else if ( param1 > CHANNELS_MAXPAYMENTS) return eval->Invalid("too many payment increments!"); else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0) return eval->Invalid("invalid open txid!"); - else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') + else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O') return eval->Invalid("invalid channelopen OP_RETURN data!"); else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0) return eval->Invalid("invalid close txid!"); - else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C') + else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C') return eval->Invalid("invalid channelclose OP_RETURN data!"); else if (tmp_txid!=opentxid) return eval->Invalid("invalid close tx, opentxid do not match on close and refund!"); @@ -338,7 +369,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("vout amount does not match number_of_payments*payment!"); else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0) { - if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) + if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0) return eval->Invalid("invalid previous tx OP_RETURN data!"); else if (tx.vout[0].scriptPubKey != prevTx.vout[1].scriptPubKey) return eval->Invalid("invalid destination for sender marker!"); @@ -351,9 +382,9 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & default: fprintf(stderr,"illegal channels funcid.(%c)\n",funcid); return eval->Invalid("unexpected channels funcid"); - break; } - } else return eval->Invalid("unexpected channels missing funcid"); + } + else return eval->Invalid("unexpected channels missing funcid"); retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) fprintf(stderr,"Channel tx validated\n"); @@ -368,14 +399,15 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, CTransaction openTx, uint256 &prevtxid, CPubKey mypk) { - char coinaddr[65]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t marker,param1; + char coinaddr[65]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3,tokenid; CTransaction tx; int32_t marker,param1; std::vector > unspentOutputs; CPubKey srcpub,destpub; uint8_t myprivkey[32]; - if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)=='O') + if ((numvouts=openTx.vout.size()) > 0 && DecodeChannelsOpRet(openTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3)=='O') { - GetCCaddress1of2(cp,coinaddr,srcpub,destpub); + if (tokenid!=zeroid) GetTokensCCaddress1of2(cp,coinaddr,srcpub,destpub); + else GetCCaddress1of2(cp,coinaddr,srcpub,destpub); SetCCunspents(unspentOutputs,coinaddr); } else @@ -389,7 +421,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C { if ( (int32_t)it->first.index==0 && GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (tmp_txid==openTx.GetHash() || tx.GetHash()==openTx.GetHash()) && (totalinputs=IsChannelsvout(cp,tx,srcpub,destpub,0)+IsChannelsMarkervout(cp,tx,srcpub,marker))>0) { @@ -407,7 +439,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C const CTransaction &txmempool = e.GetTx(); const uint256 &hash = txmempool.GetHash(); - if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 && + if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) != 0 && tmp_txid==openTx.GetHash() && param1 < mindepth) { txid=hash; @@ -421,19 +453,19 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C prevtxid=txid; mtx.vin.push_back(CTxIn(txid,0,CScript())); mtx.vin.push_back(CTxIn(txid,marker,CScript())); - Myprivkey(myprivkey); - CCaddr2set(cp,EVAL_CHANNELS,srcpub,myprivkey,coinaddr); - CCaddr3set(cp,EVAL_CHANNELS,destpub,myprivkey,coinaddr); + Myprivkey(myprivkey); + if (tokenid!=zeroid) CCaddrTokens1of2set(cp,srcpub,destpub,coinaddr); + else CCaddr1of2set(cp,srcpub,destpub,coinaddr); return totalinputs; } else return 0; } -std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment) +std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64_t payment, uint256 tokenid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - uint8_t hash[32],hashdest[32]; uint64_t funds; int32_t i; uint256 hashchain,entropy,hentropy; - CPubKey mypk; struct CCcontract_info *cp,C; + uint8_t hash[32],hashdest[32]; uint64_t amount,tokens=0,funds; int32_t i; uint256 hashchain,entropy,hentropy; + CPubKey mypk; struct CCcontract_info *cp,*cpTokens,C,CTokens; if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS ) { @@ -442,11 +474,18 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 return(""); } cp = CCinit(&C,EVAL_CHANNELS); + cpTokens = CCinit(&CTokens,EVAL_TOKENS); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); funds = numpayments * payment; - if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 ) + if (tokenid!=zeroid) + { + amount=AddNormalinputs(mtx,mypk,3*txfee,5); + tokens=AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, funds, 64); + } + else amount=AddNormalinputs(mtx,mypk,funds+3*txfee,64); + if (amount+tokens >= funds+2*txfee) { hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1); endiancpy(hash,(uint8_t *)&hentropy,32); @@ -456,10 +495,12 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 memcpy(hash,hashdest,32); } endiancpy((uint8_t *)&hashchain,hashdest,32); - mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub)); + if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub)); + else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',zeroid,mypk,destpub,numpayments,payment,hashchain))); + if (tokenid!=zeroid && tokens>funds) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,tokens-funds,mypk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',tokenid,zeroid,mypk,destpub,numpayments,payment,hashchain))); } return(""); } @@ -467,7 +508,7 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint256 secret) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3; + CPubKey mypk,srcpub,destpub; uint256 txid,hashchain,gensecret,hashblock,entropy,hentropy,prevtxid,param3,tokenid; struct CCcontract_info *cp,C; int32_t i,funcid,prevdepth,numvouts,numpayments,totalnumpayments; int64_t payment,change,funds,param2; uint8_t hash[32],hashdest[32]; @@ -482,83 +523,85 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 fprintf(stderr, "invalid channel open txid\n"); return (""); } + if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O') + { + if (mypk != srcpub && mypk != destpub) + { + fprintf(stderr,"this is not our channel\n"); + return(""); + } + else if (amount % payment != 0 || amount 0) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && (change=funds-amount-txfee)>=0) - { - if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O') + { + numpayments=amount/payment; + if (GetTransaction(prevtxid,prevTx,hashblock,false) != 0 && (numvouts=prevTx.vout.size()) > 0 && + ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) && + (funcid == 'P' || funcid=='O')) { - if (mypk != srcpub && mypk != destpub) + if (numpayments > prevdepth) { - fprintf(stderr,"this is not our channel\n"); - return(""); - } - else if (amount % payment != 0 || amount 0 && - ((funcid = DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, prevdepth, param2, param3)) != 0) && - (funcid == 'P' || funcid=='O')) + if (secret!=zeroid) { - if (numpayments > prevdepth) + endiancpy(hash, (uint8_t * ) & secret, 32); + for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++) { - fprintf(stderr,"not enough funds in channel for that amount\n"); - return (""); - } else if (numpayments == 0) - { - fprintf(stderr,"invalid amount\n"); - return (""); + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); } - if (secret!=zeroid) + endiancpy((uint8_t * ) & gensecret, hashdest, 32); + if (gensecret!=hashchain) { - endiancpy(hash, (uint8_t * ) & secret, 32); - for (i = 0; i < totalnumpayments-(prevdepth-numpayments); i++) - { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); - } - endiancpy((uint8_t * ) & gensecret, hashdest, 32); - if (gensecret!=hashchain) - { - fprintf(stderr,"invalid secret supplied\n"); - return(""); - } - } - else - { - hentropy = DiceHashEntropy(entropy,channelOpenTx.vin[0].prevout.hash,channelOpenTx.vin[0].prevout.n,1); - if (prevdepth-numpayments) - { - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < prevdepth-numpayments; i++) - { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); - } - endiancpy((uint8_t * ) & secret, hashdest, 32); - } - else endiancpy((uint8_t * ) & secret, (uint8_t * ) & hentropy, 32); + fprintf(stderr,"invalid secret supplied\n"); + return(""); } } else { - fprintf(stderr,"invalid previous tx\n"); - return(""); + hentropy = DiceHashEntropy(entropy,channelOpenTx.vin[0].prevout.hash,channelOpenTx.vin[0].prevout.n,1); + if (prevdepth-numpayments) + { + endiancpy(hash, (uint8_t * ) & hentropy, 32); + for (i = 0; i < prevdepth-numpayments; i++) + { + vcalc_sha256(0, hashdest, hash, 32); + memcpy(hash, hashdest, 32); + } + endiancpy((uint8_t * ) & secret, hashdest, 32); + } + else endiancpy((uint8_t * ) & secret, (uint8_t * ) & hentropy, 32); } } else { - fprintf(stderr, "invalid channel open tx\n"); - return (""); - } - mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub)); + fprintf(stderr,"invalid previous tx\n"); + return(""); + } + if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub)); + else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,srcpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); - return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', opentxid, srcpub, destpub, prevdepth-numpayments, numpayments, secret))); + if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, destpub)); + else mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); + return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', tokenid, opentxid, srcpub, destpub, prevdepth-numpayments, numpayments, secret))); } else { @@ -575,7 +618,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk,srcpub,destpub; struct CCcontract_info *cp,C; CTransaction channelOpenTx; - uint256 hashblock,tmp_txid,prevtxid,hashchain; + uint256 hashblock,tmp_txid,prevtxid,hashchain,tokenid; int32_t numvouts,numpayments; int64_t payment,funds; @@ -589,7 +632,7 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) fprintf(stderr, "invalid channel open txid\n"); return (""); } - if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O') + if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O') { fprintf(stderr, "invalid channel open tx\n"); return (""); @@ -603,10 +646,11 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds-txfee>0) { - mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub)); + if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub)); + else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',opentxid,mypk,destpub,(funds-txfee)/payment,payment,zeroid))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',tokenid,opentxid,mypk,destpub,(funds-txfee)/payment,payment,zeroid))); } else { @@ -623,10 +667,9 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CPubKey mypk; struct CCcontract_info *cp,C; int64_t funds,payment,param2; int32_t i,numpayments,numvouts,param1; - uint256 hashchain,hashblock,txid,prevtxid,param3,entropy,hentropy,secret; + uint256 hashchain,hashblock,txid,prevtxid,param3,tokenid; CTransaction channelOpenTx,channelCloseTx,prevTx; CPubKey srcpub,destpub; - uint8_t funcid,hash[32],hashdest[32];; // verify stoptxid and origtxid match and are mine cp = CCinit(&C,EVAL_CHANNELS); @@ -638,7 +681,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) fprintf(stderr, "invalid channel close txid\n"); return (""); } - if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,param1,param2,param3)!='C') + if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,param1,param2,param3)!='C') { fprintf(stderr, "invalid channel close tx\n"); return (""); @@ -653,7 +696,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) fprintf(stderr, "invalid channel open txid\n"); return (""); } - if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,txid,srcpub,destpub,numpayments,payment,hashchain)!='O') + if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,numpayments,payment,hashchain)!='O') { fprintf(stderr, "invalid channel open tx\n"); return (""); @@ -668,20 +711,13 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds-txfee>0) { if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 && - DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3) != 0) + DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, param1, param2, param3) != 0) { - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash, channelOpenTx.vin[0].prevout.n,1); - endiancpy(hash, (uint8_t * ) & hentropy, 32); - for (i = 0; i < param1; i++) - { - vcalc_sha256(0, hashdest, hash, 32); - memcpy(hash, hashdest, 32); - } - endiancpy((uint8_t * ) & secret, hashdest, 32); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); - mtx.vout.push_back(CTxOut(funds-txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',opentxid,mypk,destpub,param1,payment,closetxid))); + if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,funds-txfee,mypk)); + else mtx.vout.push_back(CTxOut(funds-txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',tokenid,opentxid,mypk,destpub,param1,payment,closetxid))); } else { @@ -699,7 +735,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) } UniValue ChannelsList() { - UniValue result(UniValue::VOBJ); std::vector > txids; struct CCcontract_info *cp,C; uint256 txid,hashBlock,tmp_txid,param3; + UniValue result(UniValue::VOBJ); std::vector > txids; struct CCcontract_info *cp,C; uint256 txid,hashBlock,tmp_txid,param3,tokenid; CTransaction tx; char myCCaddr[65],addr[65],str[256]; CPubKey mypk,srcpub,destpub; int32_t vout,numvouts,param1; int64_t nValue,param2; @@ -716,7 +752,7 @@ UniValue ChannelsList() nValue = (int64_t)it->second; if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O') + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O') { GetCCaddress1of2(cp,addr,srcpub,destpub); sprintf(str,"%s - %lld payments of %lld satoshi",addr,(long long)param1,(long long)param2); @@ -729,16 +765,16 @@ UniValue ChannelsList() UniValue ChannelsInfo(uint256 channeltxid) { - UniValue result(UniValue::VOBJ),array(UniValue::VARR); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid; + UniValue result(UniValue::VOBJ),array(UniValue::VARR); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid,tokenid; struct CCcontract_info *cp,C; char CCaddr[65],addr[65],str[512]; int32_t vout,numvouts,param1,numpayments; - int64_t nValue,param2,payment; CPubKey srcpub,destpub,mypk; + int64_t param2,payment; CPubKey srcpub,destpub,mypk; std::vector > addressIndex; std::vector txids; cp = CCinit(&C,EVAL_CHANNELS); mypk = pubkey2pk(Mypubkey()); if (GetTransaction(channeltxid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && - (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'O')) + (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'O')) { GetCCaddress(cp,CCaddr,mypk); Getscriptaddress(addr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); @@ -746,13 +782,22 @@ UniValue ChannelsInfo(uint256 channeltxid) result.push_back(Pair("Channel CC address",CCaddr)); result.push_back(Pair("Destination address",addr)); result.push_back(Pair("Number of payments",param1)); - result.push_back(Pair("Denomination",i64tostr(param2)+" satoshi")); - result.push_back(Pair("Amount",i64tostr(param1*param2)+" satoshi")); + if(tokenid!=zeroid) + { + result.push_back(Pair("Token id",tokenid.GetHex().data())); + result.push_back(Pair("Denomination (token satoshi)",i64tostr(param2))); + result.push_back(Pair("Amount (token satoshi)",i64tostr(param1*param2))); + } + else + { + result.push_back(Pair("Denomination (satoshi)",i64tostr(param2))); + result.push_back(Pair("Amount (satoshi)",i64tostr(param1*param2))); + } SetCCtxids(addressIndex,CCaddr); for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { if (GetTransaction(it->first.txhash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (tmp_txid==channeltxid || tx.GetHash()==channeltxid)) + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3)!=0 && (tmp_txid==channeltxid || tx.GetHash()==channeltxid)) txids.push_back(it->first.txhash); } BOOST_FOREACH(const CTxMemPoolEntry &e, mempool.mapTx) @@ -760,7 +805,7 @@ UniValue ChannelsInfo(uint256 channeltxid) const CTransaction &txmempool = e.GetTx(); const uint256 &hash = txmempool.GetHash(); - if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'P' && tmp_txid==channeltxid) + if ((numvouts=txmempool.vout.size()) > 0 && DecodeChannelsOpRet(txmempool.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'P' && tmp_txid==channeltxid) txids.push_back(hash); } prevtxid=zeroid; @@ -770,14 +815,14 @@ UniValue ChannelsInfo(uint256 channeltxid) if (txid!=prevtxid && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 ) { UniValue obj(UniValue::VOBJ); - if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O' && tx.GetHash()==channeltxid) + if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O' && tx.GetHash()==channeltxid) { obj.push_back(Pair("Open",txid.GetHex().data())); } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'P' && opentxid==channeltxid) + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'P' && opentxid==channeltxid) { if (GetTransaction(opentxid,opentx,hashBlock,false) != 0 && (numvouts=opentx.vout.size()) > 0 && - DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') + DecodeChannelsOpRet(opentx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain) == 'O') { Getscriptaddress(str,tx.vout[3].scriptPubKey); obj.push_back(Pair("Payment",txid.GetHex().data())); @@ -788,11 +833,11 @@ UniValue ChannelsInfo(uint256 channeltxid) obj.push_back(Pair("Payments left",param1)); } } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'C' && opentxid==channeltxid) + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'C' && opentxid==channeltxid) { obj.push_back(Pair("Close",txid.GetHex().data())); } - else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,opentxid,srcpub,destpub,param1,param2,param3) == 'R' && opentxid==channeltxid) + else if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,opentxid,srcpub,destpub,param1,param2,param3) == 'R' && opentxid==channeltxid) { Getscriptaddress(str,tx.vout[2].scriptPubKey); obj.push_back(Pair("Refund",txid.GetHex().data())); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6bc267e0f..6928f4361 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5840,8 +5840,10 @@ UniValue channelsinfo(const UniValue& params, bool fHelp) UniValue channelsopen(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); int32_t numpayments; int64_t payment; std::vector destpub; struct CCcontract_info *cp,C; std::string hex; + uint256 tokenid=zeroid; + cp = CCinit(&C,EVAL_CHANNELS); - if ( fHelp || params.size() != 3 ) + if ( fHelp || params.size() < 3 || params.size() > 4) throw runtime_error("channelsopen destpubkey numpayments payment\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -5865,7 +5867,11 @@ UniValue channelsopen(const UniValue& params, bool fHelp) ERR_RESULT("invalid payment amount, must be greater than 0"); return result; } - hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment); + if (params.size()==4) + { + tokenid=Parseuint256((char *)params[3].get_str().c_str()); + } + hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment,tokenid); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); @@ -5878,7 +5884,7 @@ UniValue channelspayment(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); struct CCcontract_info *cp,C; std::string hex; uint256 opentxid,secret=zeroid; int32_t n; int64_t amount; cp = CCinit(&C,EVAL_CHANNELS); - if ( fHelp || params.size() != 2 ) + if ( fHelp || params.size() < 2 || params.size() >3 ) throw runtime_error("channelspayment opentxid amount [secret]\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -6979,7 +6985,6 @@ UniValue tokenbalance(const UniValue& params, bool fHelp) UniValue result(UniValue::VOBJ); uint256 tokenid; uint64_t balance; std::vector pubkey; struct CCcontract_info *cp,C; CCerror.clear(); - cp = CCinit(&C,EVAL_ASSETS); if ( fHelp || params.size() > 2 ) throw runtime_error("tokenbalance tokenid [pubkey]\n"); if ( ensure_CCrequirements() < 0 ) @@ -6999,7 +7004,7 @@ UniValue tokenbalance(const UniValue& params, bool fHelp) char destaddr[64]; result.push_back(Pair("result", "success")); - + cp = CCinit(&C,EVAL_TOKENS); if (GetCCaddress(cp, destaddr, pubkey2pk(pubkey)) != 0) result.push_back(Pair("CCaddress", destaddr)); From 778bc04009daa6bda59498543f34b55a3c65cac6 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 18:37:51 +0500 Subject: [PATCH 086/106] corr cpAssets use for 'S' in AssetValidate --- src/cc/CCassets.h | 2 +- src/cc/CCassetsCore.cpp | 11 ++++++----- src/cc/assets.cpp | 8 ++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/cc/CCassets.h b/src/cc/CCassets.h index 39644efc6..69fcfacbb 100644 --- a/src/cc/CCassets.h +++ b/src/cc/CCassets.h @@ -44,7 +44,7 @@ bool SetAskFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValu bool SetSwapFillamounts(int64_t &paid,int64_t &remaining_price,int64_t orig_nValue,int64_t &received,int64_t totalprice); int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid); int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid); -bool AssetExactAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid); +bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 assetid); // CCassetstx //int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); // --> GetTokenBalance() diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 7084b1483..4ea025c10 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -389,13 +389,14 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch return eval->Invalid("vin1 needs to be buyvin.vout[0]"); else if ( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash,vinTx,hashBlock) == 0 ) { - int32_t z; + /* int32_t z; for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&tx.vin[vini].prevout.hash)[z]); - fprintf(stderr," vini.%d\n",vini); + fprintf(stderr," vini.%d\n",vini); */ + std::cerr << "AssetValidateCCvin cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl; return eval->Invalid("always should find CCvin, but didnt"); } - else if ( Getscriptaddress(destaddr,vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 ) + else if ( Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 ) { fprintf(stderr,"AssetValidateCCvin cc addr %s is not evalcode 0x%02x unspendable %s\n", destaddr, (int)cp->evalcode, (char *)cp->unspendableCCaddr); return eval->Invalid("invalid vin AssetsCCaddr"); @@ -404,7 +405,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch // return eval->Invalid("invalid dust for buyvin"); else if ( GetAssetorigaddrs(cp,CCaddr,origaddr,vinTx) == 0 ) return eval->Invalid("couldnt get origaddr for buyvin"); - fprintf(stderr,"Got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr); + fprintf(stderr,"AssetValidateCCvin got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr); if ( vinTx.vout[0].nValue == 0 ) return eval->Invalid("null value CCvin"); return(vinTx.vout[0].nValue); @@ -533,7 +534,7 @@ int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector tmporigpubkey; int64_t tmpprice; int32_t numvins = tx.vin.size(); diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index aab0a234f..4a5202c44 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -176,7 +176,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti if( assetid == zero ) return eval->Invalid("illegal assetid"); - else if (!AssetExactAmounts(cpAssets, inputs, outputs, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs + else if (!AssetCalcAmounts(cpAssets, inputs, outputs, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs return false; // returns false if some problems with reading vintxes } } @@ -334,7 +334,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //'S'.vout.2: vin.2 value to original pubkey [origpubkey] //vout.3: normal output for change (if any) //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - if( (assetoshis = AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) + if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillask"); @@ -352,8 +352,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("normal vout1 for fillask"); else if( remaining_price != 0 ) { - if ( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr,0) == 0 ) - return eval->Invalid("mismatched vout0 TokenCCaddr for fill"); + if ( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) + return eval->Invalid("mismatched vout0 assets unspendable CCaddr for fill sell"); } } fprintf(stderr,"fill validated\n"); From 401737d20804ee173c86df513d3054d9feeb609f Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 18:52:38 +0500 Subject: [PATCH 087/106] corr dualevalUnspendableAddr in AssetValidateCCvin --- src/cc/CCassetsCore.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 4ea025c10..ebb9ff262 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -381,8 +381,11 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,co int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx) { - uint256 hashBlock; char destaddr[64]; + uint256 hashBlock; + char destaddr[64], dualEvalUnspendableAddr[64]; + origaddr[0] = destaddr[0] = CCaddr[0] = 0; + if ( tx.vin.size() < 2 ) return eval->Invalid("not enough for CC vins"); else if ( tx.vin[vini].prevout.n != 0 ) @@ -396,7 +399,9 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch std::cerr << "AssetValidateCCvin cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl; return eval->Invalid("always should find CCvin, but didnt"); } - else if ( Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || strcmp(destaddr,(char *)cp->unspendableCCaddr) != 0 ) + else if ( Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || + !GetTokensCCaddress(cp, dualEvalUnspendableAddr, GetUnspendable(cp, NULL)) || + strcmp(destaddr, dualEvalUnspendableAddr) != 0 ) { fprintf(stderr,"AssetValidateCCvin cc addr %s is not evalcode 0x%02x unspendable %s\n", destaddr, (int)cp->evalcode, (char *)cp->unspendableCCaddr); return eval->Invalid("invalid vin AssetsCCaddr"); @@ -441,9 +446,9 @@ int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpp { CTransaction vinTx; int64_t nValue,assetoshis; //fprintf(stderr,"AssetValidateSellvin\n"); - if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 ) + if ( (nValue = AssetValidateCCvin(cp, eval, CCaddr, origaddr, tx, 1, vinTx)) == 0 ) return(0); - if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey,vinTx,0,assetid)) == 0 ) + if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey, vinTx, 0, assetid)) == 0 ) return eval->Invalid("invalid missing CC vout0 for sellvin"); else return(assetoshis); From 0588f5dc67a8c6de01690f48ac2960b72b41a527 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 19:21:41 +0500 Subject: [PATCH 088/106] corr unspendable addr for 'S' --- src/cc/CCassetsCore.cpp | 17 +++++++++-------- src/cc/assets.cpp | 5 ++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index ebb9ff262..34d773d28 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -365,14 +365,15 @@ bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CT bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx) { - uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector origpubkey; + uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; + std::vector origpubkey; CScript script; uint8_t evalCode; n = tx.vout.size(); - if ( n == 0 || (funcid= DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode,assetid,assetid2,price,origpubkey)) == 0 ) + if( n == 0 || (funcid= DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 ) return(false); - if ( GetCCaddress(cp, CCaddr, pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG) != 0 ) + if( GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG) != 0 ) return(true); else return(false); @@ -386,11 +387,11 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch origaddr[0] = destaddr[0] = CCaddr[0] = 0; - if ( tx.vin.size() < 2 ) + if( tx.vin.size() < 2 ) return eval->Invalid("not enough for CC vins"); - else if ( tx.vin[vini].prevout.n != 0 ) + else if( tx.vin[vini].prevout.n != 0 ) return eval->Invalid("vin1 needs to be buyvin.vout[0]"); - else if ( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash,vinTx,hashBlock) == 0 ) + else if( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash, vinTx,hashBlock) == 0 ) { /* int32_t z; for (z=31; z>=0; z--) @@ -399,7 +400,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch std::cerr << "AssetValidateCCvin cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl; return eval->Invalid("always should find CCvin, but didnt"); } - else if ( Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || + else if( Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || !GetTokensCCaddress(cp, dualEvalUnspendableAddr, GetUnspendable(cp, NULL)) || strcmp(destaddr, dualEvalUnspendableAddr) != 0 ) { @@ -408,7 +409,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch } //else if ( vinTx.vout[0].nValue < 10000 ) // return eval->Invalid("invalid dust for buyvin"); - else if ( GetAssetorigaddrs(cp,CCaddr,origaddr,vinTx) == 0 ) + else if( GetAssetorigaddrs(cp, CCaddr, origaddr, vinTx) == 0 ) return eval->Invalid("couldnt get origaddr for buyvin"); fprintf(stderr,"AssetValidateCCvin got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr); if ( vinTx.vout[0].nValue == 0 ) diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 4a5202c44..4efd555b7 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -334,6 +334,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //'S'.vout.2: vin.2 value to original pubkey [origpubkey] //vout.3: normal output for change (if any) //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] + char dualEvalUnspendableAddr[64]; + GetTokensCCaddress(cpAssets, dualEvalUnspendableAddr, GetUnspendable(cpAssets, NULL)); + if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) @@ -352,7 +355,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("normal vout1 for fillask"); else if( remaining_price != 0 ) { - if ( ConstrainVout(tx.vout[0], 1, (char *)cpAssets->unspendableCCaddr, 0) == 0 ) + if ( ConstrainVout(tx.vout[0], 1, dualEvalUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 ) return eval->Invalid("mismatched vout0 assets unspendable CCaddr for fill sell"); } } From 06e5d6fc6e2229867872ac536b4bc98c8038fec1 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 19:39:56 +0500 Subject: [PATCH 089/106] corr dualUnspendable use in AssetOrders --- src/cc/CCassetstx.cpp | 5 ++++- src/cc/assets.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 5b21fc1b1..5246f3d79 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -165,7 +165,10 @@ UniValue AssetOrders(uint256 refassetid) SetCCunspents(unspentOutputsTokens, (char *)cpTokens->unspendableCCaddr); - SetCCunspents(unspentOutputsAssets, (char *)cpAssets->unspendableCCaddr); + + char dualEvalUnspendableAddr[64]; + GetTokensCCaddress(cpAssets, dualEvalUnspendableAddr, GetUnspendable(cpAssets, NULL)); + SetCCunspents(unspentOutputsAssets, dualEvalUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/); for (std::vector >::const_iterator itTokens = unspentOutputsTokens.begin(); itTokens != unspentOutputsTokens.end(); diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 4efd555b7..d9e8ca7fb 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -356,12 +356,13 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti else if( remaining_price != 0 ) { if ( ConstrainVout(tx.vout[0], 1, dualEvalUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 ) - return eval->Invalid("mismatched vout0 assets unspendable CCaddr for fill sell"); + return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell"); } } fprintf(stderr,"fill validated\n"); break; case 'E': // fillexchange + ////////// not implemented yet //////////// return eval->Invalid("unexpected assets fillexchange funcid"); break; // disable asset swaps //vin.0: normal input @@ -377,6 +378,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //if ( AssetExactAmounts(false, cp,inputs,outputs,eval,tx,assetid2) == false ) // eval->Invalid("asset2 inputs != outputs"); + ////////// not implemented yet //////////// if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) @@ -412,6 +414,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("mismatched vout0 AssetsCCaddr for fillex"); } } + ////////// not implemented yet //////////// fprintf(stderr,"fill validated\n"); break; From c18a655baf63c1037a147d46d2c51e3850a119ef Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 21:14:36 +0500 Subject: [PATCH 090/106] corr uninited cpAssets var in FillBuyOffer --- src/cc/CCassetstx.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 5246f3d79..fb6b5b6db 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -621,12 +621,12 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f //CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); uint8_t unspendableAssetsPrivkey[32]; - cpTokens = CCinit(&assetsC, EVAL_ASSETS); //??? + cpAssets = CCinit(&assetsC, EVAL_ASSETS); //??? CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens paid + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the buyer if (CCchange != 0) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout3 change in single-eval tokens From 9293af0f1b1774e99dc166f07c3a62a5ba0a9119 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 22:10:25 +0500 Subject: [PATCH 091/106] added conditions for x S o B in AssetValidateCCvin --- src/cc/CCassetsCore.cpp | 57 ++++++++++++++++++++++++++++++----------- src/cc/assets.cpp | 6 +++-- 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 34d773d28..0c01f52bb 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -371,7 +371,7 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,co uint8_t evalCode; n = tx.vout.size(); - if( n == 0 || (funcid= DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 ) + if( n == 0 || (funcid = DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 ) return(false); if( GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG) != 0 ) return(true); @@ -382,11 +382,25 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,co int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx) { - uint256 hashBlock; - char destaddr[64], dualEvalUnspendableAddr[64]; + uint256 hashBlock; + uint256 assetid, assetid2; + int64_t tmpprice; + std::vector tmporigpubkey; + uint8_t evalCode; + + char destaddr[64], unspendableAddr[64]; origaddr[0] = destaddr[0] = CCaddr[0] = 0; + uint8_t funcid = 0; + if (tx.vout.size() > 0) { + uint256 assetid, assetid2; + int64_t tmpprice; + std::vector tmporigpubkey; + uint8_t evalCode; + funcid = DecodeAssetTokenOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey); + } + if( tx.vin.size() < 2 ) return eval->Invalid("not enough for CC vins"); else if( tx.vin[vini].prevout.n != 0 ) @@ -400,13 +414,25 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch std::cerr << "AssetValidateCCvin cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl; return eval->Invalid("always should find CCvin, but didnt"); } - else if( Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || - !GetTokensCCaddress(cp, dualEvalUnspendableAddr, GetUnspendable(cp, NULL)) || - strcmp(destaddr, dualEvalUnspendableAddr) != 0 ) + // if fillSell or cancelSell --> to spend tokens from dual-eval token-assets unspendable addr + else if( (funcid == 'S' || funcid == 'x') && + (Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || + !GetTokensCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) || + strcmp(destaddr, unspendableAddr) != 0)) { - fprintf(stderr,"AssetValidateCCvin cc addr %s is not evalcode 0x%02x unspendable %s\n", destaddr, (int)cp->evalcode, (char *)cp->unspendableCCaddr); + fprintf(stderr,"AssetValidateCCvin cc addr %s is not dual token-evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr); return eval->Invalid("invalid vin AssetsCCaddr"); } + // if fillBuy or cancelBuy --> to spend coins from asset unspendable addr + else if ((funcid == 'B' || funcid == 'o') && + (Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 || + !GetCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) || + strcmp(destaddr, unspendableAddr) != 0)) + { + fprintf(stderr, "AssetValidateCCvin cc addr %s is not evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr); + return eval->Invalid("invalid vin AssetsCCaddr"); + } + //else if ( vinTx.vout[0].nValue < 10000 ) // return eval->Invalid("invalid dust for buyvin"); else if( GetAssetorigaddrs(cp, CCaddr, origaddr, vinTx) == 0 ) @@ -423,11 +449,12 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr CCaddr[0] = origaddr[0] = 0; // validate locked coins on Assets vin[1] - if ( (nValue= AssetValidateCCvin(cp,eval,CCaddr,origaddr,tx,1,vinTx)) == 0 ) + if ( (nValue= AssetValidateCCvin(cp, eval, CCaddr, origaddr, tx, 1, vinTx)) == 0 ) return(0); else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("invalid normal vout0 for buyvin"); - else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' && vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'? + else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' && + vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'? return eval->Invalid("invalid normal vout1 for buyvin"); else { @@ -467,7 +494,7 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr if ((funcid = DecodeAssetTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0) { - std::cerr << "ValidateAssetOpret() DecodeOpret returned null for n-1=" << n - 1 << " txid=" << tx.GetHash().GetHex() << std::endl; + std::cerr << "ValidateAssetOpret() DecodeAssetTokenOpRet returned null for the opret for txid=" << tx.GetHash().GetHex() << std::endl; return(false); } /* it is now on token level: @@ -559,7 +586,7 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t // 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))) { - std::cerr << "AssetExactAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl; + std::cerr << "AssetCalcAmounts() cannot read vintx for i." << i << " numvins." << numvins << std::endl; return (!eval) ? false : eval->Invalid("always should find vin tx, but didnt"); } else { @@ -573,7 +600,7 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t assetoshis = IsTokensvout(false, false, cpTokens, NULL, /* vopretExtra,*/ vinTx, tx.vin[i].prevout.n, assetid, vinPubkeysEmpty); if (assetoshis != 0) { - std::cerr << "AssetExactAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl; + std::cerr << "AssetCalcAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl; inputs += assetoshis; } } @@ -595,18 +622,18 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t if (assetoshis != 0) { - std::cerr << "AssetExactAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl; + std::cerr << "AssetCalcAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl; outputs += assetoshis; } } - std::cerr << "AssetExactAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; + std::cerr << "AssetCalcAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; /* we do not verify inputs == outputs here, it's done in Tokens: if (inputs != outputs) { if (tx.GetHash() != assetid) { - std::cerr << "AssetExactAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; + std::cerr << "AssetCalcAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl; return (!eval) ? false : eval->Invalid("assets cc inputs != cc outputs"); } } */ diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index d9e8ca7fb..8d9b696e6 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -261,12 +261,12 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("locked value doesnt match vout0+1 fillbuy"); else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, 0) == 0 ) // tokens on user cc addr + if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, 0) == 0 ) // tokens on user cc addr return eval->Invalid("vout2 doesnt go to origpubkey fillbuy"); else if ( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy"); } - else if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, inputs) == 0 ) // tokens on user cc addr + else if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, inputs) == 0 ) // tokens on user cc addr return eval->Invalid("vout2 doesnt match inputs fillbuy"); else if( ConstrainVout(tx.vout[1],0,0,0) == 0 ) return eval->Invalid("vout1 is CC for fillbuy"); @@ -390,6 +390,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti if( assetoshis != tx.vout[0].nValue + tx.vout[1].nValue ) return eval->Invalid("locked value doesnt match vout0+1 fillex"); else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) + ////////// not implemented yet //////////// { if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, 0) == 0 ) return eval->Invalid("vout2 doesnt go to origpubkey fillex"); @@ -399,6 +400,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("asset inputs doesnt match vout2+3 fillex"); } } + ////////// not implemented yet //////////// else if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, inputs) == 0 ) return eval->Invalid("vout2 doesnt match inputs fillex"); else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 ) From a99fd7502d6ed0a2779f2b36f7bc110630609fad Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 22:39:21 +0500 Subject: [PATCH 092/106] added conds for ask/bid in GetAssetorigaddrs --- src/cc/CCassetsCore.cpp | 19 ++++++++++++++++--- src/cc/assets.cpp | 8 +++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 0c01f52bb..9df24b94a 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -353,6 +353,7 @@ uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOp return (uint8_t)0; } +// extract sell/buy owner's pubkey from the opret bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CTransaction &tx) { uint256 assetid,assetid2; @@ -362,8 +363,9 @@ bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CT else return(false); } - -bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,const CTransaction& tx) + +// Calculate sell/buy owner's source token/asset address from ask/bid tx +bool GetAssetorigaddrs(struct CCcontract_info *cp, char *CCaddr, char *destaddr, const CTransaction& tx) { uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector origpubkey; @@ -373,7 +375,18 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp,char *CCaddr,char *destaddr,co n = tx.vout.size(); if( n == 0 || (funcid = DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 ) return(false); - if( GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey)) != 0 && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG) != 0 ) + + bool bGetCCaddr = false; + if (funcid == 's' || funcid == 'S') + bGetCCaddr = GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey)); + else if (funcid == 'b' || funcid == 'B') + bGetCCaddr = GetCCaddress(cp, CCaddr, pubkey2pk(origpubkey)); + else { + std::cerr << "GetAssetorigaddrs incorrect funcid=" << (char)(funcid?funcid:' ') << std::endl; + return false; + } + + if( bGetCCaddr && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG)) return(true); else return(false); diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 8d9b696e6..074c617cb 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -334,8 +334,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //'S'.vout.2: vin.2 value to original pubkey [origpubkey] //vout.3: normal output for change (if any) //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - char dualEvalUnspendableAddr[64]; - GetTokensCCaddress(cpAssets, dualEvalUnspendableAddr, GetUnspendable(cpAssets, NULL)); + if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); @@ -355,7 +354,10 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("normal vout1 for fillask"); else if( remaining_price != 0 ) { - if ( ConstrainVout(tx.vout[0], 1, dualEvalUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 ) + char tokensUnspendableAddr[64]; + GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL)); + + if ( ConstrainVout(tx.vout[0], 1, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 ) return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell"); } } From 9584d6db7fd47a268d527f223f23b495b251e586 Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 22:56:30 +0500 Subject: [PATCH 093/106] corr cond (single tokens) for buy in GetAssetorigaddrs --- src/cc/CCassetsCore.cpp | 7 +++++-- src/cc/CCassetstx.cpp | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 9df24b94a..5c48837a1 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -379,8 +379,11 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp, char *CCaddr, char *destaddr, bool bGetCCaddr = false; if (funcid == 's' || funcid == 'S') bGetCCaddr = GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey)); - else if (funcid == 'b' || funcid == 'B') - bGetCCaddr = GetCCaddress(cp, CCaddr, pubkey2pk(origpubkey)); + else if (funcid == 'b' || funcid == 'B') { + struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + bGetCCaddr = GetCCaddress(cpTokens, CCaddr, pubkey2pk(origpubkey)); + } else { std::cerr << "GetAssetorigaddrs incorrect funcid=" << (char)(funcid?funcid:' ') << std::endl; return false; diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index fb6b5b6db..e60ebf3e6 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -723,8 +723,8 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a if (assetid2 != zeroid && inputs > paid_nValue) CCchange = (inputs - paid_nValue); - mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // vout.0 tokens cc addr - ask remainder - mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, received_assetoshis, mypk)); //vout.1 tokens to self + mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // vout.0 tokens remainder to unspendable cc addr + mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, received_assetoshis, mypk)); //vout.1 purchased tokens to self // NOTE: no marker here @@ -735,7 +735,7 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a } else { std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl; - mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins normal to whom who asked token + mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins to tokens seller's normal addr } // not implemented From f79531a29a3e6f5272d4519eb94be8d78aa1d74b Mon Sep 17 00:00:00 2001 From: dimxy Date: Wed, 16 Jan 2019 23:50:42 +0500 Subject: [PATCH 094/106] corr asset unspents addr in AssetOrders --- src/cc/CCassetstx.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index e60ebf3e6..39153f28f 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -164,11 +164,13 @@ UniValue AssetOrders(uint256 refassetid) }; - SetCCunspents(unspentOutputsTokens, (char *)cpTokens->unspendableCCaddr); + char assetsUnspendableAddr[64]; + GetCCaddress(cpAssets, assetsUnspendableAddr, GetUnspendable(cpAssets, NULL)); + SetCCunspents(unspentOutputsAssets, assetsUnspendableAddr /*(char *)cpTokens->unspendableCCaddr*/); - char dualEvalUnspendableAddr[64]; - GetTokensCCaddress(cpAssets, dualEvalUnspendableAddr, GetUnspendable(cpAssets, NULL)); - SetCCunspents(unspentOutputsAssets, dualEvalUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/); + char tokensUnspendableAddr[64]; + GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL)); + SetCCunspents(unspentOutputsAssets, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/); for (std::vector >::const_iterator itTokens = unspentOutputsTokens.begin(); itTokens != unspentOutputsTokens.end(); From 9657b5ce43473d979e8157f71f2978605a470978 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 00:19:33 +0500 Subject: [PATCH 095/106] added CCaddr2set to CancelSell --- src/cc/CCassetstx.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 39153f28f..6a66bfcb7 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -530,7 +530,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector dummyOrigpubkey; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); + cpAssets = CCinit(&assetsC, EVAL_ASSETS); if (txfee == 0) txfee = 10000; @@ -555,16 +555,25 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid) std::vector voutTokenPubkeys; voutTokenPubkeys.push_back(mypk); - char myCCaddr[65]; + /* char myCCaddr[65]; uint8_t myPrivkey[32]; Myprivkey(myPrivkey); cpAssets = CCinit(&assetsC, EVAL_ASSETS); - GetCCaddress(cpAssets, myCCaddr, mypk); + GetCCaddress(cpAssets, myCCaddr, mypk); */ // this is only for unspendable addresses: //CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress - return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee, + uint8_t unspendableAssetsPrivkey[32]; + char unspendableAssetsAddr[64]; + // init assets 'unspendable' privkey and pubkey + CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); + GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); + + // add additional eval-tokens unspendable assets privkey: + CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); + + return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee, EncodeTokenOpRet(assetid, voutTokenPubkeys, EncodeAssetOpRet('x', zeroid, 0, Mypubkey())))); } @@ -749,11 +758,11 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a uint8_t unspendableAssetsPrivkey[32]; char unspendableAssetsAddr[64]; - // init 'unspenable' privkey and pubkey + // init assets 'unspendable' privkey and pubkey CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, unspendableAssetsPrivkey); GetCCaddress(cpAssets, unspendableAssetsAddr, unspendableAssetsPk); - // add additional dual-eval (assets+tokens) unspendable assets address's privkey: + // add additional eval-tokens unspendable assets privkey: CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr); // vout verification pubkeys: From 29052b079061d07c1a4a53c8ed0ab4ea90e96f35 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 12:46:01 +0500 Subject: [PATCH 096/106] corr 'x' validation code corr logging in FinalizeCCtx --- src/cc/CCtx.cpp | 10 +++++----- src/cc/assets.cpp | 20 ++++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 2959ba7d7..2116e350b 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -163,19 +163,19 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = myprivkey; cond = mytokenscond; - fprintf(stderr,"FinalizeCCTx() matched TokensCC1vout CC addr.(%s)\n",mytokensaddr); + fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout CC addr.(%s)\n",mytokensaddr); } else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout { privkey = myprivkey; cond = mysingletokenscond; - fprintf(stderr, "FinalizeCCTx() matched single-eval TokensCC1vout CC addr.(%s)\n", mytokensaddr); + fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout CC addr.(%s)\n", mytokensaddr); } else if ( strcmp(destaddr,unspendable) == 0 ) { privkey = unspendablepriv; cond = othercond; - //fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable); + fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable); } else if (strcmp(destaddr, tokensunspendable) == 0) { @@ -186,7 +186,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran // check if this is the 2nd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr2) == 0) { - //fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2); + fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2); privkey = cp->unspendablepriv2; if ( othercond2 == 0 ) othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2); @@ -195,7 +195,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran // check if this is 3rd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 ) { - //fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3); + fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3); privkey = cp->unspendablepriv3; if ( othercond3 == 0 ) othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3); diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 074c617cb..ec3266c71 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -153,7 +153,11 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 ) return eval->Invalid("AssetValidate: invalid opreturn payload"); - // find token user cc addr + // find dual-eval tokens unspendable addr: + char tokensUnspendableAddr[64]; + GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL)); + + // find token user cc addr: GetCCaddress(cpTokens, tokensCCaddr, pubkey2pk(origpubkey)); fprintf(stderr,"AssetValidate (%c)\n",funcid); @@ -296,10 +300,10 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("illegal null remaining_price for selloffer"); if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) return eval->Invalid("invalid normal vout1 for sellvin"); - if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) + if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // cc change { preventCCvouts++; - if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also vout[0] + if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also cc vout[0] return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer"); else if( tx.vout[0].nValue + tx.vout[2].nValue != inputs ) return eval->Invalid("mismatched vout0+vout2 total for selloffer"); @@ -317,7 +321,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.1: vin.2 back to users pubkey //vout.2: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] - if( (assetoshis= AssetValidateSellvin(cpTokens, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) + + if( (assetoshis= AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( ConstrainVout(tx.vout[0], 1, tokensCCaddr, assetoshis) == 0 ) return eval->Invalid("invalid vout for cancel"); @@ -335,7 +340,6 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.3: normal output for change (if any) //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) @@ -354,9 +358,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti return eval->Invalid("normal vout1 for fillask"); else if( remaining_price != 0 ) { - char tokensUnspendableAddr[64]; - GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL)); - + //char tokensUnspendableAddr[64]; + //GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL)); if ( ConstrainVout(tx.vout[0], 1, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 ) return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell"); } @@ -411,6 +414,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti if( ValidateSwapRemainder(remaining_price, tx.vout[0].nValue, assetoshis,tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) return eval->Invalid("mismatched remainder for fillex"); else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 ) + ////////// not implemented yet //////////// return eval->Invalid("normal vout1 for fillex"); else if( remaining_price != 0 ) { From a645af7ee4efccaedd1f306b23904ccbe3987620 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 13:14:03 +0500 Subject: [PATCH 097/106] corrected user cc addr for 'x' --- src/cc/assets.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index ec3266c71..33798196f 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -133,14 +133,10 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid, evalCodeInOpret; - char destaddr[64], origaddr[64], assetsCCaddr[64], tokensCCaddr[64]; + char destaddr[64], origaddr[64], assetsCCaddr[64], tokensCCaddr[64], signleEvalTokensCCaddr[64]; //return true; - // we need this for validating tokens' vins/vous: - struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - //CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL); //CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, NULL); //GetCCaddress(cpTokens, tokensUnspendableCCaddr, unspendableTokensPk); @@ -157,8 +153,12 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti char tokensUnspendableAddr[64]; GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL)); - // find token user cc addr: - GetCCaddress(cpTokens, tokensCCaddr, pubkey2pk(origpubkey)); + // we need this for validating single-eval tokens' vins/vous: + struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + + // find single-eval token user cc addr: + GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey)); fprintf(stderr,"AssetValidate (%c)\n",funcid); @@ -322,9 +322,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.2: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] - if( (assetoshis= AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) + if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) // NOTE: return(false); - else if( ConstrainVout(tx.vout[0], 1, tokensCCaddr, assetoshis) == 0 ) + else if( ConstrainVout(tx.vout[0], 1, signleEvalTokensCCaddr, assetoshis) == 0 ) return eval->Invalid("invalid vout for cancel"); preventCCvins = 3; preventCCvouts = 1; From 65dfecadf8c2125a5506b4426ac7444f0e87bc6f Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 15:05:55 +0500 Subject: [PATCH 098/106] corr userCCaddr calc --- src/cc/CCassetsCore.cpp | 12 ++++++++---- src/cc/CCutils.cpp | 2 +- src/cc/assets.cpp | 17 ++++++++++------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index 5c48837a1..a99817d72 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -365,7 +365,7 @@ bool SetAssetOrigpubkey(std::vector &origpubkey,int64_t &price,const CT } // Calculate sell/buy owner's source token/asset address from ask/bid tx -bool GetAssetorigaddrs(struct CCcontract_info *cp, char *CCaddr, char *destaddr, const CTransaction& tx) +bool GetAssetorigaddrs(struct CCcontract_info *cp, char *userCCaddr, char *destaddr, const CTransaction& tx) { uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid; std::vector origpubkey; @@ -377,12 +377,16 @@ bool GetAssetorigaddrs(struct CCcontract_info *cp, char *CCaddr, char *destaddr, return(false); bool bGetCCaddr = false; - if (funcid == 's' || funcid == 'S') - bGetCCaddr = GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey)); + if (funcid == 's' || funcid == 'S') { + struct CCcontract_info *cpTokens, tokensC; + cpTokens = CCinit(&tokensC, EVAL_TOKENS); + bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey)); + //bGetCCaddr = GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey)); + } else if (funcid == 'b' || funcid == 'B') { struct CCcontract_info *cpTokens, tokensC; cpTokens = CCinit(&tokensC, EVAL_TOKENS); - bGetCCaddr = GetCCaddress(cpTokens, CCaddr, pubkey2pk(origpubkey)); + bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey)); } else { std::cerr << "GetAssetorigaddrs incorrect funcid=" << (char)(funcid?funcid:' ') << std::endl; diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index ed02a779c..5d72b6b53 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -406,7 +406,7 @@ bool ConstrainVout(CTxOut vout, int32_t CCflag, char *cmpaddr, int64_t nValue) } else if ( cmpaddr != 0 && (Getscriptaddress(destaddr, vout.scriptPubKey) == 0 || strcmp(destaddr, cmpaddr) != 0) ) { - fprintf(stderr,"constrain vout error addr %s vs %s\n", cmpaddr!=0?cmpaddr:"", destaddr!=0?destaddr:""); + 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) || ( diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 33798196f..d2eaf39de 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -133,7 +133,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid, evalCodeInOpret; - char destaddr[64], origaddr[64], assetsCCaddr[64], tokensCCaddr[64], signleEvalTokensCCaddr[64]; + char destaddr[64], origaddr[64], assetsCCaddr[64], userTokensCCaddr[64], signleEvalTokensCCaddr[64]; //return true; @@ -146,6 +146,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti outputs = inputs = 0; preventCCvins = preventCCvouts = -1; + if (numvouts == 0) + return eval->Invalid("AssetValidate: no vouts"); + if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 ) return eval->Invalid("AssetValidate: invalid opreturn payload"); @@ -322,9 +325,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.2: normal output for change (if any) //vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid] - if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) // NOTE: + if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 ) // NOTE: return(false); - else if( ConstrainVout(tx.vout[0], 1, signleEvalTokensCCaddr, assetoshis) == 0 ) + else if( ConstrainVout(tx.vout[0], 1, userTokensCCaddr, assetoshis) == 0 ) return eval->Invalid("invalid vout for cancel"); preventCCvins = 3; preventCCvouts = 1; @@ -340,7 +343,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti //vout.3: normal output for change (if any) //'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey] - if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) + if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillask"); @@ -384,7 +387,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti // eval->Invalid("asset2 inputs != outputs"); ////////// not implemented yet //////////// - if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, tokensCCaddr, origaddr, tx, assetid)) == 0 ) + if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 ) return(false); else if( numvouts < 3 ) return eval->Invalid("not enough vouts for fillex"); @@ -397,7 +400,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) ////////// not implemented yet //////////// { - if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, 0) == 0 ) + if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, 0) == 0 ) return eval->Invalid("vout2 doesnt go to origpubkey fillex"); else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) { @@ -406,7 +409,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti } } ////////// not implemented yet //////////// - else if( ConstrainVout(tx.vout[2], 1, tokensCCaddr, inputs) == 0 ) + else if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, inputs) == 0 ) return eval->Invalid("vout2 doesnt match inputs fillex"); else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 ) return eval->Invalid("vout1 is CC for fillex"); From c51e2394005e6a98da0b0cd084d90090f0190a05 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 15:19:29 +0500 Subject: [PATCH 099/106] corr FillSell self now single-eval token addr --- src/cc/CCassetstx.cpp | 2 +- src/cc/assets.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 6a66bfcb7..ed5c28fd1 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -735,7 +735,7 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a CCchange = (inputs - paid_nValue); mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // vout.0 tokens remainder to unspendable cc addr - mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, received_assetoshis, mypk)); //vout.1 purchased tokens to self + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //vout.1 purchased tokens to self single-eval addr // NOTE: no marker here diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index d2eaf39de..3ccafa34f 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -133,7 +133,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts; int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector origpubkey,tmporigpubkey,ignorepubkey; uint8_t funcid, evalCodeInOpret; - char destaddr[64], origaddr[64], assetsCCaddr[64], userTokensCCaddr[64], signleEvalTokensCCaddr[64]; + char destaddr[64], origaddr[64], assetsCCaddr[64], userTokensCCaddr[64]; //, signleEvalTokensCCaddr[64]; //return true; @@ -161,7 +161,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti cpTokens = CCinit(&tokensC, EVAL_TOKENS); // find single-eval token user cc addr: - GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey)); + //GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey)); fprintf(stderr,"AssetValidate (%c)\n",funcid); From 7c16ba9ca21d6b85a015b8e044338dcda80b0f90 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 18:36:03 +0500 Subject: [PATCH 100/106] some debug loggin removed --- src/cc/CCassetsCore.cpp | 13 +++---------- src/cc/CCtokens.cpp | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/cc/CCassetsCore.cpp b/src/cc/CCassetsCore.cpp index a99817d72..f4293eb27 100644 --- a/src/cc/CCassetsCore.cpp +++ b/src/cc/CCassetsCore.cpp @@ -616,7 +616,7 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t std::vector vopretExtra; std::vector vinPubkeysEmpty; - // TODO: why is IsTokensVout here?? + // TODO: maybe we do not need call to IsTokensVout here, cause we've already selected token vins assetoshis = IsTokensvout(false, false, cpTokens, NULL, /* vopretExtra,*/ vinTx, tx.vin[i].prevout.n, assetid, vinPubkeysEmpty); if (assetoshis != 0) { @@ -627,15 +627,8 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t } } - // we do not use this flag anymore - //if ( DecodeAssetOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,id,id2,tmpprice,tmporigpubkey) == 't' && id == assetid ) - //flag = 1; - //else - //flag = 0; - - for (int32_t i = 0; i vinPubkeys; - if ((nValue = IsTokensvout(true, true/*<--add only checked uxtos */, cp, NULL, /*vopretExtra,*/ vintx, vout, tokenid, vinPubkeys)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) + if ((nValue = IsTokensvout(true, true/*<--add only checked token uxtos */, cp, NULL, vintx, vout, tokenid)) > 0 && myIsutxo_spentinmempool(txid, vout) == 0) { if (total != 0 && maxinputs != 0) mtx.vin.push_back(CTxIn(txid, vout, CScript())); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 48dc543ab..2b882f95b 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -540,7 +540,6 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, uint256 tokenid; uint256 fundingTxidInOpret; uint8_t hasHeirSpendingBegunDummy; - std::vector vinPubkeysEmpty; CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); // check boundary uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, false); @@ -548,7 +547,7 @@ template int64_t Add1of2AddressInputs(struct CCcontract_info* cp, if ((txid == fundingtxid || fundingTxidInOpret == fundingtxid) && funcId != 0 && isMyFuncId(funcId) && - (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid, vinPubkeysEmpty) > 0) && // token validation logic + (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid) > 0) && // token validation logic //(voutValue = IsHeirFundingVout(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && // heir contract vout validation logic - not used since we moved to 2-eval vouts !myIsutxo_spentinmempool(txid, voutIndex)) { From 9dc403f33153695810fc59b8b5899cab6e53030f Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 19:42:02 +0500 Subject: [PATCH 102/106] corr call to IsTokenVout in heir --- src/cc/heir.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 2b882f95b..76b2e5537 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -588,7 +588,6 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info uint256 tokenid; uint256 fundingTxidInOpret; uint8_t hasHeirSpendingBegunDummy; - std::vector vinPubkeysEmpty; const int32_t ivout = 0; CScript heirScript = (heirtx.vout.size() > 0) ? heirtx.vout[heirtx.vout.size() - 1].scriptPubKey : CScript(); // check boundary @@ -599,7 +598,7 @@ template int64_t LifetimeHeirContractFunds(struct CCcontract_info if (funcId != 0 && (txid == fundingtxid || fundingTxidInOpret == fundingtxid) && isMyFuncId(funcId) && !isSpendingTx(funcId) && - (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, ivout, tokenid, vinPubkeysEmpty) > 0) && + (typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, ivout, tokenid) > 0) && !myIsutxo_spentinmempool(txid, ivout)) // exclude tx in mempool { total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change) From 4b71e625573aff67c2661fb240e1f6741efe7770 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 20:27:19 +0500 Subject: [PATCH 103/106] disabled debug loggin in FinalizeCCtx --- src/cc/CCtx.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 2116e350b..1ca4fbf91 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -153,7 +153,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey); //fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr); - std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " myaddr=" << myaddr << std::endl; + //std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " myaddr=" << myaddr << std::endl; if( strcmp(destaddr,myaddr) == 0 ) { privkey = myprivkey; @@ -163,30 +163,30 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { privkey = myprivkey; cond = mytokenscond; - fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout CC addr.(%s)\n",mytokensaddr); + //fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout CC addr.(%s)\n",mytokensaddr); } else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout { privkey = myprivkey; cond = mysingletokenscond; - fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout CC addr.(%s)\n", mytokensaddr); + //fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout CC addr.(%s)\n", mytokensaddr); } else if ( strcmp(destaddr,unspendable) == 0 ) { privkey = unspendablepriv; cond = othercond; - fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable); + //fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable); } else if (strcmp(destaddr, tokensunspendable) == 0) { privkey = unspendablepriv; cond = othertokenscond; - fprintf(stderr,"FinalizeCCTx() matched tokensunspendable CC addr.(%s)\n",unspendable); + //fprintf(stderr,"FinalizeCCTx() matched tokensunspendable CC addr.(%s)\n",unspendable); } // check if this is the 2nd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr2) == 0) { - fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2); + //fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2); privkey = cp->unspendablepriv2; if ( othercond2 == 0 ) othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2); @@ -195,7 +195,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran // check if this is 3rd additional evalcode + 'unspendable' cc addr: else if ( strcmp(destaddr,cp->unspendableaddr3) == 0 ) { - fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3); + //fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3); privkey = cp->unspendablepriv3; if ( othercond3 == 0 ) othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3); @@ -204,7 +204,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran // check if this is spending from 1of2 cc coins addr: else if (strcmp(cp->coins1of2addr, destaddr) == 0) { - fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr); + //fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr); privkey = myprivkey; if (othercond1of2 == 0) othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]); @@ -213,7 +213,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran // check if this is spending from 1of2 cc tokens addr: else if (strcmp(cp->tokens1of2addr, destaddr) == 0) { - fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr); + //fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr); privkey = myprivkey; if (othercond1of2tokens == 0) othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->tokens1of2pk[0], cp->tokens1of2pk[1]); From 80a1ef04f2a2ffcddaa2712bedc49dd5c486894e Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 20:41:18 +0500 Subject: [PATCH 104/106] added proc of incorrect tokenid to tokenorders --- src/wallet/rpcwallet.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6928f4361..0710bc698 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6974,9 +6974,13 @@ UniValue tokenorders(const UniValue& params, bool fHelp) throw runtime_error("tokenorders [tokenid]\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - if ( params.size() == 1 ) - tokenid = Parseuint256((char *)params[0].get_str().c_str()); - else memset(&tokenid,0,sizeof(tokenid)); + if (params.size() == 1) { + tokenid = Parseuint256((char *)params[0].get_str().c_str()); + if (tokenid == zeroid) + throw runtime_error("incorrect tokenid\n"); + } + else + memset(&tokenid,0,sizeof(tokenid)); return(AssetOrders(tokenid)); } From d63d43c8ef3d00c59871f7782dceee26099f029a Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 17 Jan 2019 22:20:11 +0500 Subject: [PATCH 105/106] heir funcs changed to one set --- src/cc/CCHeir.h | 17 +- src/cc/heir.cpp | 415 ++++++++++++++++++++------------------- src/cc/heir_validate.h | 2 +- src/rpc/server.cpp | 4 +- src/rpc/server.h | 3 - src/wallet/rpcwallet.cpp | 299 ++-------------------------- 6 files changed, 239 insertions(+), 501 deletions(-) diff --git a/src/cc/CCHeir.h b/src/cc/CCHeir.h index 8399474a7..ecaff9cdb 100644 --- a/src/cc/CCHeir.h +++ b/src/cc/CCHeir.h @@ -27,19 +27,10 @@ bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, class CoinHelper; class TokenHelper; -// CCcustom - -// this would not link -//template std::string HeirFund(uint64_t txfee,int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); -//template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount); -//template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t nValue); - -UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); -UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 assetid); -UniValue HeirClaimCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); -UniValue HeirClaimTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); -UniValue HeirAddCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); -UniValue HeirAddTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); +UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid); +UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid); +UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); +UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); UniValue HeirInfo(uint256 fundingtxid); UniValue HeirList(); diff --git a/src/cc/heir.cpp b/src/cc/heir.cpp index 76b2e5537..4a78c69ac 100644 --- a/src/cc/heir.cpp +++ b/src/cc/heir.cpp @@ -14,8 +14,6 @@ ******************************************************************************/ #include "CCHeir.h" -#include "CCtokens.h" - #include "heir_validate.h" class CoinHelper; @@ -122,27 +120,27 @@ bool HeirValidate(struct CCcontract_info* cpHeir, Eval* eval, const CTransaction //if (chainActive.Height() < 741) // return true; - uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenid = zeroid; + uint256 fundingTxidInOpret = zeroid, latestTxid = zeroid, dummyTokenid, tokenidThis, tokenid = zeroid; CScript fundingTxOpRetScript; uint8_t hasHeirSpendingBegun = 0, hasHeirSpendingBegunDummy; CScript opret = (tx.vout.size() > 0) ? tx.vout[tx.vout.size() - 1].scriptPubKey : CScript(); // check boundary - uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, fundingTxidInOpret, hasHeirSpendingBegunDummy, true); + uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenidThis, fundingTxidInOpret, hasHeirSpendingBegunDummy, true); if (funcId == 0) return eval->Invalid("invalid opreturn format"); if (funcId != 'F') { if (fundingTxidInOpret == zeroid) { - return eval->Invalid("invalid tx opreturn format: no fundingtxid present"); + return eval->Invalid("incorrect tx opreturn: no fundingtxid present"); } - if (tokenid == zeroid) - latestTxid = FindLatestFundingTx(fundingTxidInOpret, dummyTokenid, fundingTxOpRetScript, hasHeirSpendingBegun); - else - latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, hasHeirSpendingBegun); + latestTxid = FindLatestFundingTx(fundingTxidInOpret, tokenid, fundingTxOpRetScript, hasHeirSpendingBegun); + + if( tokenid != zeroid && tokenid != tokenidThis ) + return eval->Invalid("incorrect tx tokenid"); if (latestTxid == zeroid) { - return eval->Invalid("invalid heir transaction: no funding tx found"); + return eval->Invalid("no fundingtx found"); } } else { @@ -406,7 +404,7 @@ uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &f * find the latest funding tx: it may be the first F tx or one of A or C tx's * Note: this function is also called from validation code (use non-locking calls) */ -template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun) +uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun) { CTransaction fundingtx; uint256 hashBlock; @@ -489,7 +487,7 @@ template uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_ } // overload for validation code -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &hasHeirSpendingBegun) +uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &hasHeirSpendingBegun) { uint8_t funcId; CPubKey ownerPubkey; @@ -497,15 +495,15 @@ template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 int64_t inactivityTime; std::string heirName; - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); } // overload for transaction creation code -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &hasHeirSpendingBegun) +uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &hasHeirSpendingBegun) { CScript opRetScript; - return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); + return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun); } // add inputs of 1 of 2 cc address @@ -704,111 +702,115 @@ UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName * creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir * @return result object with raw tx or error text */ -template UniValue HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount) +template UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun) { - UniValue result(UniValue::VOBJ); //, a(UniValue::VARR); + UniValue result(UniValue::VOBJ); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey ownerPubkey, heirPubkey; int64_t inputs, CCchange = 0; - int64_t inactivityTimeSec; struct CCcontract_info *cp, C; std::string rawhex; - uint256 lasttxid, tokenid; - std::string heirName; - uint8_t funcId; - uint8_t hasHeirSpendingBegun = 0; cp = CCinit(&C, Helper::getMyEval()); // for tokens shoud be EVAL_TOKENS to sign it correctly! - //cp = CCinit(&C, EVAL_HEIR); // for tokens shoud be EVAL_TOKENS to sign it correctly! if (txfee == 0) txfee = 10000; - if ((lasttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { - int32_t numblocks; + CPubKey myPubkey = pubkey2pk(Mypubkey()); - CPubKey myPubkey = pubkey2pk(Mypubkey()); + // check if it is the owner + if (myPubkey != ownerPubkey) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "adding funds is only allowed for the owner of this contract")); + return result; + } - // check if it is the owner - if (myPubkey != ownerPubkey) { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "adding funds is only allowed for the owner of this contract")); - return result; - } + if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners - if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners + int64_t inputs, change; - int64_t inputs, change; + if ((inputs = Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, 64)) > 0) { // TODO: why 64 max inputs? - if ((inputs = Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, 64)) > 0) { // TODO: why 64 max inputs? + // we do not use markers anymore - storing data in opreturn is better + // add marker vout: + /* char markeraddr[64]; + CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners + std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */ - // we do not use markers anymore - storing data in opreturn is better - // add marker vout: - /* char markeraddr[64]; - CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners - std::cerr << "HeirAdd() adding markeraddr=" << markeraddr << '\n'; */ + // add cryptocondition to spend this funded amount for either pk + mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); - // add cryptocondition to spend this funded amount for either pk - mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); + if (inputs > amount) + change = (inputs - amount); // -txfee <-- txfee pays user - if (inputs > amount) - change = (inputs - amount); // -txfee <-- txfee pays user + //std::cerr << "HeirAdd() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; - //std::cerr << "HeirAdd() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; - - if (change != 0) { // vout[1] - mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); - } - - // add 1of2 vout validation pubkeys - needed only for tokens: - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(ownerPubkey); - voutTokenPubkeys.push_back(heirPubkey); - - // add opreturn 'A' and sign tx: // this txfee ignored - std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun))); - - if (!rawhextx.empty()) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hextx", rawhextx)); - } - else { - std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "sign error")); - } - + if (change != 0) { // vout[1] + mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); } - else { - std::cerr << "HeirAdd cannot find owner cc inputs" << std::endl; + + // add 1of2 vout validation pubkeys - needed only for tokens: + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(ownerPubkey); + voutTokenPubkeys.push_back(heirPubkey); + + // add opreturn 'A' and sign tx: // this txfee ignored + std::string rawhextx = (FinalizeCCTx(0, cp, mtx, myPubkey, txfee, + Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun))); + + if (!rawhextx.empty()) { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hextx", rawhextx)); + } + else { + std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find owner cc inputs")); + result.push_back(Pair("error", "sign error")); } + } else { - std::cerr << "HeirAdd cannot find normal inputs for tx fee" << std::endl; + std::cerr << "HeirAdd cannot find owner cc inputs" << std::endl; result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find normal inputs for tx fee")); + result.push_back(Pair("error", "can't find owner cc inputs")); } + } + else { + std::cerr << "HeirAdd cannot find normal inputs for tx fee" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find normal inputs for tx fee")); + } - } else { - fprintf(stderr, "HeirAdd can't find any heir CC funding tx's\n"); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find any heir CC funding transactions")); - } return result; } -UniValue HeirAddCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { - return HeirAdd(fundingtxid, txfee, amount); -} -UniValue HeirAddTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { - return HeirAdd(fundingtxid, txfee, amount); +UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { + + CPubKey ownerPubkey, heirPubkey; + int64_t inactivityTimeSec; + + uint256 latesttxid, tokenid = zeroid; + uint8_t funcId; + std::string heirName; + uint8_t hasHeirSpendingBegun = 0; + + if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { + if (tokenid == zeroid) + return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + else + return _HeirAdd(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + } + else { + UniValue result(UniValue::VOBJ); + + fprintf(stderr, "HeirAdd() can't find any heir CC funding tx's\n"); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find any heir CC funding transactions")); + return result; + } } @@ -817,146 +819,155 @@ UniValue HeirAddTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) * creates tx to spend funds from cryptocondition address by either funds' owner or heir * @return result object with raw tx or error text */ -template UniValue HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t amount) +template UniValue _HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun) { - UniValue result(UniValue::VOBJ); //, a(UniValue::VARR); + UniValue result(UniValue::VOBJ); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey myPubkey, ownerPubkey, heirPubkey; + CPubKey myPubkey; int64_t inputs, change = 0; - int64_t inactivityTimeSec; struct CCcontract_info *cp, C; - uint256 latesttxid, tokenid; - uint8_t funcId; - std::string heirName; - uint8_t hasHeirSpendingBegun = 0; - - //cp = CCinit(&C, Helper::getMyEval()); cp = CCinit(&C, EVAL_HEIR); if (txfee == 0) txfee = 10000; - if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { - int32_t numblocks; - uint64_t durationSec = 0; + int32_t numblocks; + uint64_t durationSec = 0; - // we do not need to find duration if spending already has begun - if (!hasHeirSpendingBegun) { - durationSec = CCduration(numblocks, latesttxid); - std::cerr << "HeirClaim() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << std::endl; - } + // we do not need to find duration if spending already has begun + if (!hasHeirSpendingBegun) { + durationSec = CCduration(numblocks, latesttxid); + std::cerr << "HeirClaim() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << std::endl; + } - // spending is allowed if there is already spending tx or inactivity time - //bool isAllowedToHeir = (funcId == 'C' || durationSec > inactivityTimeSec) ? true : false; - bool isAllowedToHeir = (hasHeirSpendingBegun || durationSec > inactivityTimeSec) ? true : false; - myPubkey = pubkey2pk(Mypubkey()); + // spending is allowed if there is already spending tx or inactivity time + //bool isAllowedToHeir = (funcId == 'C' || durationSec > inactivityTimeSec) ? true : false; + bool isAllowedToHeir = (hasHeirSpendingBegun || durationSec > inactivityTimeSec) ? true : false; + myPubkey = pubkey2pk(Mypubkey()); - // if it is the heir, check if spending not allowed to heir yet - if (myPubkey == heirPubkey && !isAllowedToHeir) { - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "spending is not allowed yet for the heir")); - return result; - } + // if it is the heir, check if spending not allowed to heir yet + if (myPubkey == heirPubkey && !isAllowedToHeir) { + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "spending is not allowed yet for the heir")); + return result; + } + + // we do not use markers any more: + // we allow owner to spend funds at any time: + // if it is the owner, check if spending already allowed to heir + /* if (myPubkey == ownerPubkey && isAllowedToHeir) { + result.push_back(Pair("result", "spending is not already allowed for the owner")); + return result; + } */ + + // add spending txfee from the calling user + if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { + + // add spending from cc 1of2 address + if ((inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, amount, 60)) >= amount) // TODO: why only 60 inputs? + { + /*if (inputs < amount) { + std::cerr << "HeirClaim() cant find enough HeirCC 1of2 inputs, found=" << inputs << " required=" << amount << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find heir CC funding")); - // we do not use markers any more: - // we allow owner to spend funds at any time: - // if it is the owner, check if spending already allowed to heir - /* if (myPubkey == ownerPubkey && isAllowedToHeir) { - result.push_back(Pair("result", "spending is not already allowed for the owner")); return result; - } */ + }*/ - // add spending txfee from the calling user - if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { + // add vout with amount to claiming address + mtx.vout.push_back(Helper::makeUserVout(amount, myPubkey)); // vout[0] - // add spending from cc 1of2 address - if ((inputs = Add1of2AddressInputs(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, amount, 60)) >= amount) // TODO: why only 60 inputs? - { - /*if (inputs < amount) { - std::cerr << "HeirClaim() cant find enough HeirCC 1of2 inputs, found=" << inputs << " required=" << amount << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find heir CC funding")); + // calc and add change vout: + if (inputs > amount) + change = (inputs - amount); // -txfee <-- txfee pays user - return result; - }*/ + //std::cerr << "HeirClaim() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; - // add vout with amount to claiming address - mtx.vout.push_back(Helper::makeUserVout(amount, myPubkey)); // vout[0] - - // calc and add change vout: - if (inputs > amount) - change = (inputs - amount); // -txfee <-- txfee pays user - - //std::cerr << "HeirClaim() inputs=" << inputs << " amount=" << amount << " txfee=" << txfee << " change=" << change << '\n'; - - // change to 1of2 funding addr: - if (change != 0) { // vout[1] - mtx.vout.push_back(Helper::make1of2Vout(change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! - } - - // add marker vout: - /*char markeraddr[64]; - CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); - // NOTE: amount = 0 is not working: causes error code: -26, error message : 64 : dust - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners - std::cerr << "HeirClaim() adding markeraddr=" << markeraddr << '\n'; */ - - // get address of 1of2 cond - char coinaddr[64]; - Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); - - // retrieve priv key addresses for FinalizeCCtx: - uint8_t myprivkey[32]; - Myprivkey(myprivkey); - - // set pubkeys for finding 1of2 cc in FinalizeCCtx to sign it: - Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); - - // add 1of2 vout validation pubkeys (this is for tokens): - std::vector voutTokenPubkeys; - voutTokenPubkeys.push_back(ownerPubkey); - voutTokenPubkeys.push_back(heirPubkey); - - // add opreturn 'C' and sign tx: // this txfee will be ignored - std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, - Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid, (myPubkey == heirPubkey) ? 1 : hasHeirSpendingBegun)); // forward isHeirSpending to the next latest tx - - if (!rawhextx.empty()) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hextx", rawhextx)); - } - else { - std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "sign error")); - } - - } else { - fprintf(stderr, "HeirClaim() cant find Heir CC inputs\n"); - result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find heir CC funding")); + // change to 1of2 funding addr: + if (change != 0) { // vout[1] + mtx.vout.push_back(Helper::make1of2Vout(change, ownerPubkey, heirPubkey)); // using always pubkeys from OP_RETURN in order to not mixing them up! } + + // add marker vout: + /*char markeraddr[64]; + CPubKey markerpubkey = CCtxidaddr(markeraddr, fundingtxid); + // NOTE: amount = 0 is not working: causes error code: -26, error message : 64 : dust + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(markerpubkey)) << OP_CHECKSIG)); // txfee 1, txfee 2 - for miners + std::cerr << "HeirClaim() adding markeraddr=" << markeraddr << '\n'; */ + + // get address of 1of2 cond + char coinaddr[64]; + Helper::GetCoinsOrTokensCCaddress1of2(coinaddr, ownerPubkey, heirPubkey); + + // retrieve priv key addresses for FinalizeCCtx: + uint8_t myprivkey[32]; + Myprivkey(myprivkey); + + // set pubkeys for finding 1of2 cc in FinalizeCCtx to sign it: + Helper::CCaddrCoinsOrTokens1of2set(cp, ownerPubkey, heirPubkey, coinaddr); + + // add 1of2 vout validation pubkeys (this is for tokens): + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(ownerPubkey); + voutTokenPubkeys.push_back(heirPubkey); + + // add opreturn 'C' and sign tx: // this txfee will be ignored + std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee, + Helper::makeClaimOpRet(tokenid, voutTokenPubkeys, fundingtxid, (myPubkey == heirPubkey) ? 1 : hasHeirSpendingBegun)); // forward isHeirSpending to the next latest tx + + if (!rawhextx.empty()) { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hextx", rawhextx)); + } + else { + std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "sign error")); + } + } else { - fprintf(stderr, "HeirClaim() cant find sufficient user inputs for tx fee\n"); + fprintf(stderr, "HeirClaim() cant find Heir CC inputs\n"); result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find sufficient user inputs to pay transaction fee")); + result.push_back(Pair("error", "can't find heir CC funding")); } } else { - fprintf(stderr, "HeirClaim() can't find any heir CC funding tx's\n"); + fprintf(stderr, "HeirClaim() cant find sufficient user inputs for tx fee\n"); result.push_back(Pair("result", "error")); - result.push_back(Pair("error", "can't find any heir CC funding transactions")); + result.push_back(Pair("error", "can't find sufficient user inputs to pay transaction fee")); } + return result; } -UniValue HeirClaimCoinCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { - return HeirClaim(fundingtxid, txfee, amount); -} -UniValue HeirClaimTokenCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { - return HeirClaim(fundingtxid, txfee, amount); +UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { + + CPubKey ownerPubkey, heirPubkey; + int64_t inactivityTimeSec; + + uint256 latesttxid, tokenid = zeroid; + uint8_t funcId; + std::string heirName; + uint8_t hasHeirSpendingBegun = 0; + + if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { + if( tokenid == zeroid ) + return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + else + return _HeirClaim(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + + } + else { + UniValue result(UniValue::VOBJ); + + fprintf(stderr, "HeirClaim() can't find any heir CC funding tx's\n"); + result.push_back(Pair("result", "error")); + result.push_back(Pair("error", "can't find any heir CC funding transactions")); + return result; + } } + /** * heirinfo rpc call implementation * returns some information about heir CC contract plan by a handle of initial fundingtxid: @@ -980,32 +991,28 @@ UniValue HeirInfo(uint256 fundingtxid) if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) { CPubKey ownerPubkey, heirPubkey; - uint256 latestFundingTxid; uint256 dummyTokenid, tokenid = zeroid; // important to clear tokenid std::string heirName; int64_t inactivityTimeSec; const bool noLogging = false; + uint8_t funcId; - - CScript opret = fundingtx.vout.size() > 0 ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); + /*CScript opret = fundingtx.vout.size() > 0 ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript(); uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true); if (funcId == 0) { std::cerr << "HeirInfo() this fundingtx is incorrect" << std::endl; result.push_back(Pair("result", "error")); result.push_back(Pair("error", "initial tx F not found")); return result; - } + }*/ struct CCcontract_info *cp, C; cp = CCinit(&C, EVAL_HEIR); uint8_t hasHeirSpendingBegun = 0; - if (tokenid == zeroid) // coins - latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, dummyTokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); - else // tokens - latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid /*<-verify for tokens*/, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); - + uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); + if (latestFundingTxid != zeroid) { int32_t numblocks; uint64_t durationSec = 0; diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index f091e1381..88c02f239 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -10,7 +10,7 @@ CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName); CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan); -template uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, 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, bool noLogging = false); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 5c32b2f5a..5761b5bf7 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -411,9 +411,9 @@ static const CRPCCommand vRPCCommands[] = { "heir", "heirfund", &heirfund, true }, { "heir", "heiradd", &heiradd, true }, { "heir", "heirclaim", &heirclaim, true }, - { "heir", "heirfundtokens", &heirfundtokens, true }, +/* { "heir", "heirfundtokens", &heirfundtokens, true }, { "heir", "heiraddtokens", &heiraddtokens, true }, - { "heir", "heirclaimtokens", &heirclaimtokens, true }, + { "heir", "heirclaimtokens", &heirclaimtokens, true },*/ { "heir", "heirinfo", &heirinfo, true }, { "heir", "heirlist", &heirlist, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 7c85c43b6..99b7e8678 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -257,9 +257,6 @@ extern UniValue heiraddress(const UniValue& params, bool fHelp); extern UniValue heirfund(const UniValue& params, bool fHelp); extern UniValue heiradd(const UniValue& params, bool fHelp); extern UniValue heirclaim(const UniValue& params, bool fHelp); -extern UniValue heirfundtokens(const UniValue& params, bool fHelp); -extern UniValue heiraddtokens(const UniValue& params, bool fHelp); -extern UniValue heirclaimtokens(const UniValue& params, bool fHelp); extern UniValue heirinfo(const UniValue& params, bool fHelp); extern UniValue heirlist(const UniValue& params, bool fHelp); extern UniValue channelsaddress(const UniValue& params, bool fHelp); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0710bc698..538155331 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5417,7 +5417,6 @@ UniValue gatewaysaddress(const UniValue& params, bool fHelp) UniValue heiraddress(const UniValue& params, bool fHelp) { - /* struct CCcontract_info *cp,C; std::vector pubkey; cp = CCinit(&C,EVAL_HEIR); if ( fHelp || params.size() > 1 ) @@ -5427,131 +5426,6 @@ UniValue heiraddress(const UniValue& params, bool fHelp) if ( params.size() == 1 ) pubkey = ParseHex(params[0].get_str().c_str()); return(CCaddress(cp,(char *)"Heir",pubkey)); - */ - - - // make fake token tx: - struct CCcontract_info *cp, C; - - if (fHelp || (params.size() < 1)) - throw runtime_error("heiraddress A|G|H|T|R assetid|destpubkey amountcoins [heirpubkey] [fundingtxid]\n"); - if (ensure_CCrequirements() < 0) - throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - - char badKind = ((char *)params[0].get_str().c_str())[0]; - - if (badKind == 'A') { - std::vector destPubkey; - if (params.size() == 2) { - cp = CCinit(&C, EVAL_HEIR); - destPubkey = ParseHex(params[1].get_str().c_str()); - return(CCaddress(cp, (char *)"Heir", destPubkey)); - } - else - return std::string("bad params for A"); - } - - CPubKey myPubkey = pubkey2pk(Mypubkey()); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());; - - if (badKind != 'R') { - - if (badKind == 'G' && params.size() != 3) - return std::string("incorrect params for G"); - if (badKind == 'H' && params.size() != 5) - return std::string("incorrect params for H, = 5"); - if (badKind == 'T' && params.size() != 3) - return std::string("incorrect params for T, = 3"); - - - uint256 assetid = Parseuint256((char *)params[1].get_str().c_str()); - int64_t amount = atof(params[2].get_str().c_str()) * COIN; - - uint256 fundingtxid; - CPubKey heirPubkey; - - if (badKind == 'H') { - - std::vector heirPubkeyStr = ParseHex(params[3].get_str().c_str()); - heirPubkey = pubkey2pk(heirPubkeyStr); - - fundingtxid = Parseuint256((char *)params[4].get_str().c_str()); - } - - - - int64_t txfee = 10000; - - uint8_t evalCodeInOpret = (badKind == 'H') ? EVAL_HEIR : EVAL_GATEWAYS; - cp = CCinit(&C, EVAL_ASSETS); - - int64_t normalInputs = AddNormalinputs(mtx, myPubkey, txfee + amount, 60); - // int64_t ccInputs = 0; - - - if (badKind == 'T') { - // just empty fake token - mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, amount, myPubkey)); //note you need destPubkey for sending to gateways - } - else if (badKind == 'H') { - // heir add funding tx - mtx.vout.push_back(MakeCC1of2vout(EVAL_ASSETS, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk - } - else { // if (badKind == 'G') - CPubKey gatewayContractPubKey = GetUnspendable(cp, 0); - mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(gatewayContractPubKey)) << OP_CHECKSIG)); - } - - int64_t change = (normalInputs - amount); - if (change != 0) { - mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG)); - } - std::cerr << "make fake token for contract=" << badKind << " added normalInputs=" << normalInputs << " change=" << change << std::endl; - - // note: it sets eval=EVAL_ASSETS in opreturn both for tokens and gateways cc addr - //script = EncodeAssetOpRet('t', assetid, zeroid, 0, (badKind == 'A' ? Mypubkey() : destPubkey)); // dimxy: are we sure about destPubkey here? it may be just pubkey of the author... - CScript opret; - assetid = revuint256(assetid); - fundingtxid = revuint256(fundingtxid); - if (badKind == 'T') - opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalCodeInOpret << (uint8_t)'t' << assetid ); - else if (badKind == 'H') - opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalCodeInOpret << (uint8_t)'t' << assetid << (uint8_t)'A' << myPubkey << heirPubkey << (int64_t)120 << fundingtxid); - else - opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)evalCodeInOpret << (uint8_t)'t' << assetid); // EVAL_GATEWAYS - - return(FinalizeCCTx(0, cp, mtx, myPubkey, txfee, opret)); // normal change added here - } - else - { - // move vout from user cc addr to gateways unspendable - CTransaction srctx; - - uint256 hashBlock; - const bool allowSlow = false; - uint256 srctxid = Parseuint256((char *)params[1].get_str().c_str()); - - struct CCcontract_info *cp, C; - cp = CCinit(&C, EVAL_GATEWAYS); - - uint64_t txfee = 10000; - CPubKey gatewayspk = GetUnspendable(cp, 0); - - if (myGetTransaction(srctxid, srctx, hashBlock) && srctx.vout.size() > 0) { - - int64_t normalInputs = AddNormalinputs(mtx, myPubkey, 2 * txfee, 4); - - mtx.vin.push_back(CTxIn(srctxid, 2, CScript())); // repaired src tx - mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS, srctx.vout[2].nValue, gatewayspk)); - - CScript script = srctx.vout[srctx.vout.size() - 1].scriptPubKey; - - //mtx.fOverwintered = true; - - return(FinalizeCCTx(0, cp, mtx, myPubkey, txfee, script)); // normal change added here - } - } - return std::string("there has been some error"); } @@ -7432,53 +7306,12 @@ UniValue getbalance64(const UniValue& params, bool fHelp) return ret; } -// heir contract functions for coins + +// heir contract functions for coins and tokens UniValue heirfund(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); - //uint256 txid; - int64_t txfee; - int64_t amount; - int64_t inactivitytime; - std::string hex; - std::vector pubkey; - std::string name; - - //TODO: do we need this? - if (!EnsureWalletIsAvailable(fHelp)) - return NullUniValue; - - if (fHelp || params.size() != 5) - throw runtime_error("heirfund fee funds heirname heirpubkey inactivitytime\n"); - if (ensure_CCrequirements() < 0) - throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - - txfee = atof((char*)params[0].get_str().c_str()) * COIN; - amount = atof((char*)params[1].get_str().c_str()) * COIN; - name = params[2].get_str(); - pubkey = ParseHex(params[3].get_str().c_str()); - inactivitytime = atof((char*)params[4].get_str().c_str()); - - - result = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, zeroid); -/* if (hex.size() > 0) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } - else - ERR_RESULT("couldn't create heir fund");*/ - - return result; -} - - -UniValue heiradd(const UniValue& params, bool fHelp) -{ - UniValue result; // UniValue result(UniValue::VOBJ); - uint256 fundingtxid; + uint256 tokenid = zeroid; uint64_t txfee; int64_t amount; int64_t inactivitytime; @@ -7486,88 +7319,11 @@ UniValue heiradd(const UniValue& params, bool fHelp) std::vector pubkey; std::string name; - // TODO: do we need this? if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() != 3) - throw runtime_error("heiradd fee funds fundingtxid\n"); - if (ensure_CCrequirements() < 0) - throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - - txfee = atof((char*)params[0].get_str().c_str()) * COIN; - amount = atof((char*)params[1].get_str().c_str()) * COIN; - fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); - - result = HeirAddCoinCaller(fundingtxid, txfee, amount); - /* if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldn't claim heir fund"); */ - - - return result; -} - -UniValue heirclaim(const UniValue& params, bool fHelp) -{ - UniValue result; // result(UniValue::VOBJ); - uint256 fundingtxid; - uint64_t txfee; - int64_t amount; - int64_t inactivitytime; - std::string hex; - std::vector pubkey; - std::string name; - - // do we need this? - if (!EnsureWalletIsAvailable(fHelp)) - return NullUniValue; - - if (fHelp || params.size() != 3) - throw runtime_error("heirclaim fee funds fundingtxid\n"); - if (ensure_CCrequirements() < 0) - throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - - const CKeyStore& keystore = *pwalletMain; - LOCK2(cs_main, pwalletMain->cs_wallet); - - txfee = atof((char*)params[0].get_str().c_str()) * COIN; - amount = atof((char*)params[1].get_str().c_str()) * COIN; - fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); - - result = HeirClaimCoinCaller(fundingtxid, txfee, amount); - /* if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldn't claim heir fund"); */ - - return result; -} - -// same heir contract functions for tokens -UniValue heirfundtokens(const UniValue& params, bool fHelp) -{ - UniValue result(UniValue::VOBJ); - uint256 assetid; - uint64_t txfee; - int64_t amount; - int64_t inactivitytime; - std::string hex; - std::vector pubkey; - std::string name; - - //TODO: do we need this (dimxy)? - if (!EnsureWalletIsAvailable(fHelp)) - return NullUniValue; - - if (fHelp || params.size() != 6) - throw runtime_error("heirfundtokens fee funds heirname heirpubkey inactivitytime assetid\n"); + if (fHelp || params.size() != 5 && params.size() != 6) + throw runtime_error("heirfundtokens fee funds heirname heirpubkey inactivitytime [tokenid]\n"); if (ensure_CCrequirements() < 0) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -7578,26 +7334,27 @@ UniValue heirfundtokens(const UniValue& params, bool fHelp) amount = atoll((char*)params[1].get_str().c_str()); name = params[2].get_str(); pubkey = ParseHex(params[3].get_str().c_str()); + if( !pubkey2pk(pubkey).IsValid() ) + throw runtime_error("incorrect pubkey\n"); + inactivitytime = atof((char*)params[4].get_str().c_str()); - assetid = Parseuint256((char*)params[5].get_str().c_str()); - - - result = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, assetid); -/* if (hex.size() > 0) { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); + if (params.size() == 6) { + tokenid = Parseuint256((char*)params[5].get_str().c_str()); + if(tokenid == zeroid) + throw runtime_error("incorrect tokenid\n"); } - else - ERR_RESULT("couldn't create heir fund");*/ + if( tokenid == zeroid ) + result = HeirFundCoinCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, zeroid); + else + result = HeirFundTokenCaller(txfee, amount, name, pubkey2pk(pubkey), inactivitytime, tokenid); return result; } - -UniValue heiraddtokens(const UniValue& params, bool fHelp) +UniValue heiradd(const UniValue& params, bool fHelp) { - UniValue result; // UniValue result(UniValue::VOBJ); + UniValue result; uint256 fundingtxid; uint64_t txfee; int64_t amount; @@ -7606,7 +7363,6 @@ UniValue heiraddtokens(const UniValue& params, bool fHelp) std::vector pubkey; std::string name; - // TODO: do we need this? if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; @@ -7622,18 +7378,11 @@ UniValue heiraddtokens(const UniValue& params, bool fHelp) amount = atoll((char*)params[1].get_str().c_str()); fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); - result = HeirAddTokenCaller(fundingtxid, txfee, amount); - /* if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldn't claim heir fund"); */ - - + result = HeirAddCaller(fundingtxid, txfee, amount); return result; } -UniValue heirclaimtokens(const UniValue& params, bool fHelp) +UniValue heirclaim(const UniValue& params, bool fHelp) { UniValue result; // result(UniValue::VOBJ); uint256 fundingtxid; @@ -7660,13 +7409,7 @@ UniValue heirclaimtokens(const UniValue& params, bool fHelp) amount = atoll((char*)params[1].get_str().c_str()); fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); - result = HeirClaimTokenCaller(fundingtxid, txfee, amount); - /* if ( hex.size() > 0 ) - { - result.push_back(Pair("result", "success")); - result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldn't claim heir fund"); */ - + result = HeirClaimCaller(fundingtxid, txfee, amount); return result; } From d9de6b7cde33e0ca3987857c73cd4bf74b9370c1 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 18 Jan 2019 00:47:01 +0500 Subject: [PATCH 106/106] extra logging disabled in validator --- src/cc/heir_validate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/heir_validate.h b/src/cc/heir_validate.h index 88c02f239..d66777933 100644 --- a/src/cc/heir_validate.h +++ b/src/cc/heir_validate.h @@ -604,7 +604,7 @@ public: } } - std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl; + //std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl; return true; } virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; }