From 0acaa3517fce93f24a8050dfea7f5aa51524a27d Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 18 Apr 2019 14:23:12 +0200 Subject: [PATCH 01/43] Adding validation for importgateway CC (#22) --- src/cc/gateways.cpp | 29 ++-- src/cc/import.cpp | 303 +++++++++++++++------------------------ src/cc/importgateway.cpp | 8 +- src/importcoin.cpp | 12 +- src/importcoin.h | 4 +- src/rpc/crosschain.cpp | 1 + src/wallet/rpcwallet.cpp | 1 + 7 files changed, 143 insertions(+), 215 deletions(-) diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index e15735d70..3334255d4 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -571,8 +571,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("invalid gatewaysbind OP_RETURN data!"); else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for gatewaysbind!"); - else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for gatewaysbind!"); else if ( ConstrainVout(tmptx.vout[0],1,gatewaystokensaddr,totalsupply)==0) return eval->Invalid("invalid tokens to gateways vout for gatewaysbind!"); else if ( ConstrainVout(tmptx.vout[1],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0) @@ -599,6 +597,11 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid(validationError); } else if ( DecodeOraclesCreateOpRet(tmptx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' ) + { + sprintf(validationError,"invalid oraclescreate OP_RETURN data\n"); + return eval->Invalid(validationError); + } + else if (refcoin!=name) { sprintf(validationError,"mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str()); return eval->Invalid(validationError); @@ -632,10 +635,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("invalid gatewaysdeposittxid!"); else if (IsCCInput(tx.vin[0].scriptSig) != 0) return eval->Invalid("vin.0 is normal for gatewaysclaim!"); - else if (IsCCInput(tx.vin[1].scriptSig) == 0) - return eval->Invalid("vin.1 is CC for gatewaysclaim!"); - else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || myGetTransaction(tx.vin[2].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.2 is CC marker for gatewaysclaim or invalid marker amount!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewaysclaim or invalid marker amount!"); else if (_GetCCaddress(destaddr,EVAL_TOKENS,pubkey)==0 || ConstrainVout(tx.vout[0],1,destaddr,amount)==0) return eval->Invalid("invalid vout tokens to destpub for gatewaysclaim!"); else if (numvouts>2 && (myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || ConstrainVout(tx.vout[1],1,gatewaystokensaddr,tmptx.vout[tx.vin[1].prevout.n].nValue-amount)==0)) @@ -695,8 +696,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("refcoin different than in bind tx"); else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for gatewaysWithdraw!"); - else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for gatewaysWithdraw!"); else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0) return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); else if ( ConstrainVout(tmptx.vout[1],1,gatewaystokensaddr,amount)==0) @@ -717,8 +716,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); else if (IsCCInput(tx.vin[0].scriptSig) != 0) return eval->Invalid("vin.0 is normal for gatewayspartialsign!"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.1 is CC marker for gatewayspartialsign or invalid marker amount!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewayspartialsign or invalid marker amount!"); else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 ) return eval->Invalid("vout.0 invalid marker for gatewayspartialsign!"); else if (K>M) @@ -739,8 +738,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("refcoin different than in bind tx"); else if ( IsCCInput(tmptx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for gatewaysWithdraw!"); - else if ( IsCCInput(tmptx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for gatewaysWithdraw!"); else if ( ConstrainVout(tmptx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE)==0) return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); else if ( ConstrainVout(tmptx.vout[1],1,gatewaystokensaddr,amount)==0) @@ -761,8 +758,8 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("gatewaysbind tx is not yet confirmed(notarised)!"); else if (IsCCInput(tx.vin[0].scriptSig) != 0) return eval->Invalid("vin.0 is normal for gatewayscompletesigning!"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.1 is CC marker for gatewayscompletesigning or invalid marker amount!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewayscompletesigning or invalid marker amount!"); else if (ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,CC_MARKER_VALUE) == 0 ) return eval->Invalid("vout.0 invalid marker for gatewayscompletesigning!"); else if (KInvalid("gatewaysbind tx is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for gatewaysmarkdone!"); - else if ((*cp->ismyvin)(tx.vin[1].scriptSig) == 0 || myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[1].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.1 is CC marker for gatewaysmarkdone or invalid marker amount!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewaysmarkdone or invalid marker amount!"); else if (KInvalid("invalid number of signs!"); break; diff --git a/src/cc/import.cpp b/src/cc/import.cpp index b847e07d2..ea22f5e42 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -32,35 +32,13 @@ extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids); uint256 GatewaysReverseScan(uint256 &txid, int32_t height, uint256 reforacletxid, uint256 batontxid); int32_t GatewaysCointxidExists(struct CCcontract_info *cp, uint256 cointxid); -uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,uint256 &tokenid,std::string &coin,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &gatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype); +uint8_t DecodeImportGatewayBindOpRet(char *burnaddr,const CScript &scriptPubKey,std::string &coin,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &importgatewaypubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2,uint8_t &wiftype); +int64_t ImportGatewayVerify(char *refburnaddr,uint256 oracletxid,int32_t claimvout,std::string refcoin,uint256 burntxid,const std::string deposithex,std::vectorproof,uint256 merkleroot,CPubKey destpub,uint8_t taddr,uint8_t prefix,uint8_t prefix2); char *nonportable_path(char *str); char *portable_path(char *str); void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep); void *filestr(long *allocsizep,char *_fname); -// ac_import=chain support: -// encode opret for gateways import -CScript EncodeImportTxOpRet(uint32_t targetCCid, std::string coin, std::vector publishers, std::vectortxids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vectorproof, CPubKey destpub, int64_t amount) -{ - CScript opret; - opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount); - return(opret); -} - -CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint256 bindtxid, std::vector publishers, std::vectortxids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vectorproof, CPubKey destpub, int64_t amount) -{ - CScript opret; - opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount); - return(opret); -} - -CScript EncodeCodaImportTxOpRet(uint32_t targetCCid, std::string coin, std::string burntx, uint256 bindtxid, CPubKey destpub, int64_t amount) -{ - CScript opret; - opret << OP_RETURN << E_MARSHAL(ss << targetCCid << burntx << bindtxid << destpub << amount); - return(opret); -} - cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2,char const *arg3,char const *arg4,char const *arg5) { char cmdstr[5000],fname[256],*jsonstr; @@ -81,106 +59,6 @@ cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2, return(retjson); } -bool ImportCoinGatewaysVerify(CTransaction oracletx, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vectorproof, uint256 merkleroot) -{ - std::vector txids; - uint256 proofroot; - std::string name, description, format; - int32_t i, numvouts; - - if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin) - { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl); - return false; - } - - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in trusted merkleroot" << std::endl); - return true; -} - -// make import tx with burntx and its proof of existence -// std::string MakeGatewaysImportTx(uint64_t txfee, uint256 oracletxid, int32_t height, std::string refcoin, std::vector proof, std::string rawburntx, int32_t ivout, uint256 burntxid,std::string destaddr) -// { -// CMutableTransaction burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); -// CTransaction oracletx,regtx; CPubKey regpk; -// uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts; -// std::string name,desc,format; std::vector vouts; -// std::vector pubkeys; std::vectortxids; -// char markeraddr[64]; int64_t datafee; -// std::vector > unspentOutputs; - -// if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx)) -// return std::string(""); -// CAmount amount = GetCoinImportValue(burntx); // equal to int64_t -// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl); -// if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0) -// { -// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find oracletxid=" << oracletxid.GetHex() << std::endl); -// return(""); -// } -// if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C') -// { -// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl); -// return(""); -// } -// if (name!=refcoin || format!="Ihh") -// { -// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl); -// return(""); -// } -// CCtxidaddr(markeraddr,oracletxid); -// SetCCunspents(unspentOutputs,markeraddr,true); -// for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) -// { -// txid = it->first.txhash; -// if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0 -// && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid ) -// { -// pubkeys.push_back(regpk); -// n++; -// } -// } -// merkleroot = zeroid; -// for (i = m = 0; i < n; i++) -// { -// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl); -// if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) -// { -// if (merkleroot == zeroid) -// merkleroot = mhash, m = 1; -// else if (mhash == merkleroot) -// m ++; -// txids.push_back(txid); -// } -// } -// LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl); -// if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot -// { -// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); -// return(""); -// } -// proofroot = BitcoinGetProofMerkleRoot(proof, txids); -// if (proofroot != merkleroot) -// { -// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl); -// return(""); -// } -// // check the burntxid is in the proof: -// if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) { -// LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid proof for this burntxid=" << burntxid.GetHex() << std::endl); -// return(""); -// } -// burntx.vout.push_back(MakeBurnOutput(amount,0xffffffff,refcoin,vouts,proof,oracletxid,height)); -// std::vector leaftxids; -// BitcoinGetProofMerkleRoot(proof, leaftxids); -// MerkleBranch newBranch(0, leaftxids); -// TxProof txProof = std::make_pair(burntxid, newBranch); -// CTxDestination dest = DecodeDestination(destaddr.c_str()); -// CScript scriptPubKey = GetScriptForDestination(dest); -// vouts.push_back(CTxOut(amount,scriptPubKey)); -// return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts))); -// } - // makes source tx for self import tx std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx) { @@ -452,71 +330,118 @@ int32_t CheckCODAimport(CTransaction importTx,CTransaction burnTx,std::vector proof, - uint256 bindtxid,std::vector publishers,std::vector txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub) + uint256 bindtxid,std::vector publishers,std::vector txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount) { - // CTransaction oracletx,regtx; CPubKey regpk; - // uint256 proofroot,txid,tmporacletxid,merkleroot,mhash,hashBlock; int32_t i,m,n=0,numvouts; - // std::string name,desc,format; std::vector vouts; - // std::vector pubkeys; std::vectortxids; - // char markeraddr[64]; int64_t datafee; - // std::vector > unspentOutputs; + CTransaction oracletx,bindtx,regtx; int32_t i,m,n=0,numvouts; uint8_t M,N,taddr,prefix,prefix2,wiftype; + uint256 txid,oracletxid,tmporacletxid,merkleroot,mhash,hashBlock; + std::string name,desc,format,coin; std::vector vouts; CPubKey regpk; + std::vector pubkeys,tmppubkeys,tmppublishers; char markeraddr[64],deposit[64],destaddr[64],tmpdest[64]; int64_t datafee; + std::vector > unspentOutputs; + // ASSETCHAINS_SELFIMPORT is coin // check for valid burn from external coin blockchain and if valid return(0); - // if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0) - // { - // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl); - // return(-1); - // } - // if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C') - // { - // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl); - // return(-1); - // } - // if (name!=refcoin || format!="Ihh") - // { - // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl); - // return(-1); - // } - // CCtxidaddr(markeraddr,oracletxid); - // SetCCunspents(unspentOutputs,markeraddr,true); - // for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) - // { - // txid = it->first.txhash; - // if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0 - // && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid ) - // { - // pubkeys.push_back(regpk); - // n++; - // } - // } - // merkleroot = zeroid; - // for (i = m = 0; i < n; i++) - // { - // if ((mhash = CCOraclesReverseScan("importcoind-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) - // { - // if (merkleroot == zeroid) - // merkleroot = mhash, m = 1; - // else if (mhash == merkleroot) - // m ++; - // txids.push_back(txid); - // } - // } - // if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot - // { - // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); - // return(-1); - // } - // proofroot = BitcoinGetProofMerkleRoot(proof, txids); - // if (proofroot != merkleroot) - // { - // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl); - // return(-1); - // } - // // check the burntxid is in the proof: - // if (std::find(txids.begin(), txids.end(), burnTx.GetHash()) == txids.end()) { - // LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid proof for this burntxid=" << burnTx.GetHash().GetHex() << std::endl); - // return(-1); - // } + if (GetTransaction(bindtxid, bindtx, hashBlock, false) == 0 || (numvouts = bindtx.vout.size()) <= 0) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport cant find bindtxid=" << bindtxid.GetHex() << std::endl); + return(-1); + } + else if (DecodeImportGatewayBindOpRet(deposit,bindtx.vout[numvouts - 1].scriptPubKey,coin,oracletxid,M,N,tmppubkeys,taddr,prefix,prefix2,wiftype) != 'B') + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckGATEWAYimport invalid bind tx. bindtxid=" << bindtxid.GetHex() << std::endl); + return(-1); + } + else if (refcoin!=coin) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid coin " << refcoin << "!=" << coin << std::endl); + return(-1); + } + else if ( N == 0 || N > 15 || M > N ) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid N or M " << std::endl); + return(-1); + } + else if (tmppubkeys.size()!=N) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport not enough pubkeys for given N " << std::endl); + return(-1); + } + else if (komodo_txnotarizedconfirmed(bindtxid) == false) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport bindtx not yet confirmed/notarized" << std::endl); + return(-1); + } + else if (GetTransaction(oracletxid, oracletx, hashBlock, false) == 0 || (numvouts = oracletx.vout.size()) <= 0) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport cant find oracletxid=" << oracletxid.GetHex() << std::endl); + return(-1); + } + else if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey,name,desc,format) != 'C') + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle tx. oracletxid=" << oracletxid.GetHex() << std::endl); + return(-1); + } + else if (name!=refcoin || format!="Ihh") + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid oracle name or format tx. oracletxid=" << oracletxid.GetHex() << " name=" << name << " format=" << format << std::endl); + return(-1); + } + CCtxidaddr(markeraddr,oracletxid); + SetCCunspents(unspentOutputs,markeraddr,false); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + if ( GetTransaction(txid,regtx,hashBlock,false) != 0 && regtx.vout.size() > 0 + && DecodeOraclesOpRet(regtx.vout[regtx.vout.size()-1].scriptPubKey,tmporacletxid,regpk,datafee) == 'R' && oracletxid == tmporacletxid ) + { + pubkeys.push_back(regpk); + n++; + } + } + if (pubkeys.size()!=tmppubkeys.size()) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport different number of bind and oracle pubkeys " << tmppubkeys.size() << "!=" << pubkeys.size() << std::endl); + return(-1); + } + merkleroot = zeroid; + for (i = m = 0; i < n; i++) + { + if ((mhash = CCOraclesReverseScan("importgateway-1",txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) + { + if (merkleroot == zeroid) + merkleroot = mhash, m = 1; + else if (mhash == merkleroot) + m ++; + tmppublishers.push_back(pubkeys[i]); + } + } + if (publishers.size()!=tmppublishers.size()) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport different number of publishers for burtx in oracle" << std::endl); + return(-1); + } + else if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport couldnt find merkleroot for block height=" << height << "coin=" << refcoin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); + return(-1); + } + else if ( ImportGatewayVerify(deposit,oracletxid,burnvout,refcoin,burntxid,rawburntx,proof,merkleroot,destpub,taddr,prefix,prefix2) != amount ) + { + CCerror = strprintf("burntxid didnt validate !"); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(-1); + } + else if (importTx.vout[0].nValue!=amount) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport import amount different than in burntx" << std::endl); + return(-1); + } + Getscriptaddress(destaddr,importTx.vout[0].scriptPubKey); + Getscriptaddress(tmpdest,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); + if (strcmp(destaddr,tmpdest)!=0) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport import coins destination different than in burntx" << std::endl); + return(-1); + } return(0); } @@ -581,8 +506,8 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti */ bool Eval::ImportCoin(const std::vector params,const CTransaction &importTx,unsigned int nIn) { - TxProof proof; CTransaction burnTx; std::vector payouts; uint64_t txfee = 10000; int32_t height,burnvout; std::vector publishers; - uint32_t targetCcid; std::string targetSymbol,srcaddr,destaddr,receipt,rawburntx; uint256 payoutsHash,bindtxid; std::vector rawproof; + TxProof proof; CTransaction burnTx; std::vector payouts; int64_t txfee = 10000, amount; int32_t height,burnvout; std::vector publishers; + uint32_t targetCcid; std::string targetSymbol,srcaddr,destaddr,receipt,rawburntx; uint256 payoutsHash,bindtxid,burntxid; std::vector rawproof; std::vector txids; CPubKey destpub; if ( importTx.vout.size() < 2 ) @@ -649,7 +574,7 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo { if ( targetSymbol != ASSETCHAINS_SELFIMPORT ) return Invalid("invalid-gateway-import-coin"); - else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,height,burnvout,rawburntx,destpub) < 0 ) + else if ( UnmarshalBurnTx(burnTx,bindtxid,publishers,txids,burntxid,height,burnvout,rawburntx,destpub,amount)==0 || CheckGATEWAYimport(importTx,burnTx,targetSymbol,rawproof,bindtxid,publishers,txids,burntxid,height,burnvout,rawburntx,destpub,amount) < 0 ) return Invalid("GATEWAY-import-failure"); } } diff --git a/src/cc/importgateway.cpp b/src/cc/importgateway.cpp index f7bd9b669..c3d318ca5 100644 --- a/src/cc/importgateway.cpp +++ b/src/cc/importgateway.cpp @@ -212,7 +212,7 @@ int64_t ImportGatewayVerify(char *refburnaddr,uint256 oracletxid,int32_t claimvo } if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) { - LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify invalid proof for this burntxid" << std::endl); + LOGSTREAM("importgateway",CCLOG_INFO, stream << "ImportGatewayVerify invalid proof for this burntxid " << burntxid.GetHex() << std::endl); return 0; } if ( DecodeHexTx(tx,deposithex) != 0 ) @@ -611,18 +611,18 @@ std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height, LOGSTREAM("importgateway",CCLOG_INFO, stream << "burntxid." << burntxid.GetHex() << " m." << m << " of n." << n << std::endl); if ( merkleroot == zeroid || m < n/2 ) { - CCerror = strprintf("couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d",height,coin.c_str(),uint256_str(str,oracletxid),m,n); + CCerror = strprintf("couldnt find merkleroot for ht.%d %s oracle.%s m.%d vs n.%d",height,refcoin.c_str(),uint256_str(str,oracletxid),m,n); LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if ( ImportGatewayVerify(burnaddr,oracletxid,claimvout,coin,burntxid,rawburntx,proof,merkleroot,destpub,taddr,prefix,prefix2) != amount ) + if ( ImportGatewayVerify(burnaddr,oracletxid,claimvout,refcoin,burntxid,rawburntx,proof,merkleroot,destpub,taddr,prefix,prefix2) != amount ) { CCerror = strprintf("burntxid didnt validate!"); LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); return(""); } vouts.push_back(CTxOut(amount,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)); - burntx.vout.push_back(MakeBurnOutput((CAmount)amount,0xffffffff,refcoin,vouts,proof,bindtxid,publishers,txids,height,claimvout,rawburntx,destpub)); + burntx.vout.push_back(MakeBurnOutput((CAmount)amount,0xffffffff,refcoin,vouts,proof,bindtxid,publishers,txids,burntxid,height,claimvout,rawburntx,destpub,amount)); std::vector leaftxids; BitcoinGetProofMerkleRoot(proof, leaftxids); MerkleBranch newBranch(0, leaftxids); diff --git a/src/importcoin.cpp b/src/importcoin.cpp index 051129020..6702a78dd 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -53,7 +53,7 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb } CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof, - uint256 bindtxid,std::vector publishers,std::vector txids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub) + uint256 bindtxid,std::vector publishers,std::vector txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount) { std::vector opret; opret = E_MARSHAL(ss << VARINT(targetCCid); @@ -63,10 +63,12 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb ss << bindtxid; ss << publishers; ss << txids; + ss << burntxid; ss << height; ss << burnvout; ss << rawburntx; - ss << destpub); + ss << destpub; + ss << amount); return CTxOut(value, CScript() << OP_RETURN << opret); } @@ -125,7 +127,7 @@ bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::strin ss >> receipt)); } -bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub) +bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount) { std::vector burnOpret,rawproof; bool isEof=true; uint32_t targetCCid; uint256 payoutsHash; std::string targetSymbol; @@ -139,10 +141,12 @@ bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector> bindtxid; ss >> publishers; ss >> txids; + ss >> burntxid; ss >> height; ss >> burnvout; ss >> rawburntx; - ss >> destpub)); + ss >> destpub; + ss >> amount)); } diff --git a/src/importcoin.h b/src/importcoin.h index 8cb8dbc58..0fcc350d0 100644 --- a/src/importcoin.h +++ b/src/importcoin.h @@ -30,13 +30,13 @@ CTransaction MakeImportCoinTransaction(const TxProof proof, CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof); CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof, - uint256 bindtxid,std::vector publishers,std::vectortxids,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub); + uint256 bindtxid,std::vector publishers,std::vectortxids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount); CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof,std::string srcaddr, std::string receipt); bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector &rawproof); bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt); -bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub); +bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount); bool UnmarshalImportTx(const CTransaction importTx, TxProof &proof, CTransaction &burnTx,std::vector &payouts); bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state); diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index c7992a953..cacf4357e 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -631,6 +631,7 @@ UniValue importgatewaypartialsign(const UniValue& params, bool fHelp) coin = params[1].get_str(); parthex = params[2].get_str(); hex = ImportGatewayPartialSign(0,txid,coin,parthex); + RETURN_IF_ERROR(CCerror); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a21de63f4..847205ec1 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -6594,6 +6594,7 @@ UniValue gatewayspartialsign(const UniValue& params, bool fHelp) coin = params[1].get_str(); parthex = params[2].get_str(); hex = GatewaysPartialSign(0,txid,coin,parthex); + RETURN_IF_ERROR(CCerror); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); From 9499ddf88fd5526d7ed3ca6bca60f28a9ac8ffa5 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 18 Apr 2019 14:25:51 +0200 Subject: [PATCH 02/43] Fix --- src/cc/gateways.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index 3334255d4..d88b3d25f 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -597,10 +597,7 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid(validationError); } else if ( DecodeOraclesCreateOpRet(tmptx.vout[numvouts-1].scriptPubKey,name,description,format) != 'C' ) - { - sprintf(validationError,"invalid oraclescreate OP_RETURN data\n"); - return eval->Invalid(validationError); - } + return eval->Invalid("invalid oraclescreate OP_RETURN data"); else if (refcoin!=name) { sprintf(validationError,"mismatched oracle name %s != %s\n",name.c_str(),refcoin.c_str()); From cbf2d438ebed9486001a104c98ea1b660a8bdfca Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 Apr 2019 03:53:04 -1100 Subject: [PATCH 03/43] if ( (json= send_curl(url,(char *)"iex")) != 0 ) // --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index ed80c2a4a..546d23d86 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2017,7 +2017,7 @@ int32_t get_stockprices(uint32_t now,uint32_t *prices,std::vector s { char url[32768],*symbol,*timestr; cJSON *json,*obj; int32_t i,n=0,retval=-1; uint32_t uprice,timestamp; sprintf(url,"https://api.iextrading.com/1.0/tops/last?symbols=%s",GetArg("-ac_stocks","").c_str()); - if ( (json= send_curl(url,(char *)"iex")) != 0 ) //if ( (json= get_urljson(url)) != 0 ) + if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"iex")) != 0 ) // { if ( (n= cJSON_GetArraySize(json)) > 0 ) { From b533bc95d54a2f914c1f72f744ed6e8bb4038ec6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 Apr 2019 03:55:58 -1100 Subject: [PATCH 04/43] if ( (json= get_urljson(url)) != 0 ) --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 546d23d86..0ff1c0b66 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2056,7 +2056,7 @@ uint32_t get_dailyfx(uint32_t *prices) //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} char url[512],*datestr; cJSON *json,*rates; int32_t i; uint32_t datenum=0,price = 0; sprintf(url,"https://api.openrates.io/latest?base=USD"); - if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) + if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { if ( (rates= jobj(json,(char *)"rates")) != 0 ) { @@ -2079,7 +2079,7 @@ uint32_t get_binanceprice(const char *symbol) { char url[512]; cJSON *json; uint32_t price = 0; sprintf(url,"https://api.binance.com/api/v1/ticker/price?symbol=%sBTC",symbol); - if ( (json= send_curl(url,(char *)"bnbprice")) != 0 ) + if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"bnbprice")) != 0 ) { price = jdouble(json,(char *)"price")*SATOSHIDEN + 0.0000000049; free_json(json); From 0140f176a664bad14bb46f76a2c84085f8f3628a Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 Apr 2019 07:16:48 -1100 Subject: [PATCH 05/43] Return error in else case --- .gitignore | 2 ++ src/cc/dapps/zmigrate.c | 1 + 2 files changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6cebf87fe..d139071e0 100644 --- a/.gitignore +++ b/.gitignore @@ -155,3 +155,5 @@ src/rogue.scr src/cc/rogue/confdefs.h src/cc/rogue/x64 + +src/cc/dapps/a.out diff --git a/src/cc/dapps/zmigrate.c b/src/cc/dapps/zmigrate.c index 86626b699..33d776650 100644 --- a/src/cc/dapps/zmigrate.c +++ b/src/cc/dapps/zmigrate.c @@ -664,6 +664,7 @@ int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr) free(retstr); return(0); } + return(-1); } int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname) From 13458b404042e2a2a6865fae70c999e70d06f28c Mon Sep 17 00:00:00 2001 From: ca333 Date: Thu, 18 Apr 2019 23:15:48 +0200 Subject: [PATCH 06/43] [add] KOIN --- src/ac/koin | 2 ++ src/assetchains.json | 11 ++++++++--- src/assetchains.old | 1 + src/fiat/koin | 2 ++ 4 files changed, 13 insertions(+), 3 deletions(-) create mode 100755 src/ac/koin create mode 100755 src/fiat/koin diff --git a/src/ac/koin b/src/ac/koin new file mode 100755 index 000000000..7e76c6b54 --- /dev/null +++ b/src/ac/koin @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=KOIN $1 $2 $3 $4 $5 $6 diff --git a/src/assetchains.json b/src/assetchains.json index 87173697b..99c6557b6 100644 --- a/src/assetchains.json +++ b/src/assetchains.json @@ -237,8 +237,8 @@ "217.182.129.38", "37.187.225.231" ] - }, - { + }, + { "ac_name": "ILN", "ac_supply": "10000000000", "ac_cc": "2", @@ -258,10 +258,15 @@ "ac_cc": "3", "addnode": ["138.201.136.145"] }, -{ + { "ac_name": "VOTE2019", "ac_supply": "123651638", "ac_public": "1", "addnode": ["95.213.238.98"] + }, + { + "ac_name": "KOIN", + "ac_supply": "125000000", + "addnode": ["3.0.32.10"] } ] diff --git a/src/assetchains.old b/src/assetchains.old index 8f0d763b5..a0cbd3b9c 100755 --- a/src/assetchains.old +++ b/src/assetchains.old @@ -50,3 +50,4 @@ echo $pubkey ./komodod -pubkey=$pubkey -ac_name=RICK -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 & ./komodod -pubkey=$pubkey -ac_name=MORTY -ac_supply=90000000000 -ac_reward=100000000 -ac_cc=3 -addnode=138.201.136.145 & ./komodod -pubkey=$pubkey -ac_name=VOTE2019 -ac_supply=123651638 -ac_public=1 -addnode=95.213.238.98 & +./komodod -pubkey=$pubkey -ac_name=KOIN -ac_supply=125000000 -addnode=3.0.32.10 & diff --git a/src/fiat/koin b/src/fiat/koin new file mode 100755 index 000000000..7e76c6b54 --- /dev/null +++ b/src/fiat/koin @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=KOIN $1 $2 $3 $4 $5 $6 From b4ad109167a34a6bfcb3cfa89a53de9543cde2c4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 Apr 2019 21:59:31 -1100 Subject: [PATCH 07/43] send_curl --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0ff1c0b66..7f221f5f3 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2017,7 +2017,7 @@ int32_t get_stockprices(uint32_t now,uint32_t *prices,std::vector s { char url[32768],*symbol,*timestr; cJSON *json,*obj; int32_t i,n=0,retval=-1; uint32_t uprice,timestamp; sprintf(url,"https://api.iextrading.com/1.0/tops/last?symbols=%s",GetArg("-ac_stocks","").c_str()); - if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"iex")) != 0 ) // + if ( (json= send_curl(url,(char *)"iex")) != 0 ) //if ( (json= get_urljson(url)) != 0 ) // // { if ( (n= cJSON_GetArraySize(json)) > 0 ) { @@ -2056,7 +2056,7 @@ uint32_t get_dailyfx(uint32_t *prices) //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} char url[512],*datestr; cJSON *json,*rates; int32_t i; uint32_t datenum=0,price = 0; sprintf(url,"https://api.openrates.io/latest?base=USD"); - if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) + if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) //if ( (json= get_urljson(url)) != 0 ) // { if ( (rates= jobj(json,(char *)"rates")) != 0 ) { From 9129c28d9056b0f0d453ac289352891e122e7e5f Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 Apr 2019 22:01:07 -1100 Subject: [PATCH 08/43] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7f221f5f3..93595e25a 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2079,7 +2079,7 @@ uint32_t get_binanceprice(const char *symbol) { char url[512]; cJSON *json; uint32_t price = 0; sprintf(url,"https://api.binance.com/api/v1/ticker/price?symbol=%sBTC",symbol); - if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"bnbprice")) != 0 ) + if ( (json= send_curl(url,(char *)"bnbprice")) != 0 )//if ( (json= get_urljson(url)) != 0 ) // { price = jdouble(json,(char *)"price")*SATOSHIDEN + 0.0000000049; free_json(json); From a209aaeeb7d0984c8af54b643526caec28354e52 Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 18 Apr 2019 22:02:26 -1100 Subject: [PATCH 09/43] if ( (json= send_curl(url,(char *)"bnbprice")) != 0 ) --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 93595e25a..0ff1c0b66 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2017,7 +2017,7 @@ int32_t get_stockprices(uint32_t now,uint32_t *prices,std::vector s { char url[32768],*symbol,*timestr; cJSON *json,*obj; int32_t i,n=0,retval=-1; uint32_t uprice,timestamp; sprintf(url,"https://api.iextrading.com/1.0/tops/last?symbols=%s",GetArg("-ac_stocks","").c_str()); - if ( (json= send_curl(url,(char *)"iex")) != 0 ) //if ( (json= get_urljson(url)) != 0 ) // // + if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"iex")) != 0 ) // { if ( (n= cJSON_GetArraySize(json)) > 0 ) { @@ -2056,7 +2056,7 @@ uint32_t get_dailyfx(uint32_t *prices) //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} char url[512],*datestr; cJSON *json,*rates; int32_t i; uint32_t datenum=0,price = 0; sprintf(url,"https://api.openrates.io/latest?base=USD"); - if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) //if ( (json= get_urljson(url)) != 0 ) // + if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) { if ( (rates= jobj(json,(char *)"rates")) != 0 ) { @@ -2079,7 +2079,7 @@ uint32_t get_binanceprice(const char *symbol) { char url[512]; cJSON *json; uint32_t price = 0; sprintf(url,"https://api.binance.com/api/v1/ticker/price?symbol=%sBTC",symbol); - if ( (json= send_curl(url,(char *)"bnbprice")) != 0 )//if ( (json= get_urljson(url)) != 0 ) // + if ( (json= get_urljson(url)) != 0 ) //if ( (json= send_curl(url,(char *)"bnbprice")) != 0 ) { price = jdouble(json,(char *)"price")*SATOSHIDEN + 0.0000000049; free_json(json); From 62b4c709ca333f595ec11c1ee2fa4d555d6515ba Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 19 Apr 2019 11:22:13 +0200 Subject: [PATCH 10/43] Fix oracleslist on SetCCtxids --- src/cc/oracles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/oracles.cpp b/src/cc/oracles.cpp index 54e9202e1..ef457fe82 100644 --- a/src/cc/oracles.cpp +++ b/src/cc/oracles.cpp @@ -1028,7 +1028,7 @@ UniValue OraclesList() { UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction createtx; std::string name,description,format; char str[65]; cp = CCinit(&C,EVAL_ORACLES); - SetCCtxids(addressIndex,cp->normaladdr,true); + SetCCtxids(addressIndex,cp->normaladdr,false); for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { txid = it->first.txhash; From 4add699cbb0fc06d1b13a054523652dd872abf62 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 18 Apr 2019 16:54:32 +0500 Subject: [PATCH 11/43] token migration moved to FSM --- src/Makefile.am | 2 +- src/cc/CCinclude.h | 6 +- src/cc/CCtokens.cpp | 225 ++++-- src/cc/CCtokens.h | 1 + .../{CCtokensOpRet.cpp => CCtokenutils.cpp} | 133 +++- src/cc/CCutils.cpp | 124 ++-- src/cc/import.cpp | 333 ++++++--- src/crosschain.cpp | 123 +++- src/crosschain.h | 2 +- src/importcoin.cpp | 205 +++++- src/importcoin.h | 79 +- src/rpc/crosschain.cpp | 690 +++++++++++++++--- src/rpc/server.cpp | 3 + src/rpc/server.h | 3 + 14 files changed, 1525 insertions(+), 404 deletions(-) rename src/cc/{CCtokensOpRet.cpp => CCtokenutils.cpp} (69%) diff --git a/src/Makefile.am b/src/Makefile.am index 248f9aa27..7e1647a6c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -491,7 +491,7 @@ libbitcoin_common_a_SOURCES = \ script/sign.cpp \ script/standard.cpp \ transaction_builder.cpp \ - cc/CCtokensOpRet.cpp \ + cc/CCtokenutils.cpp \ cc/CCutilbits.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 6ca6fa3bc..5a515634d 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -206,13 +206,13 @@ int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, vscript_t vopretNonfungible); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector> oprets); -CScript EncodeTokenImportOpRet(std::vector origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector> oprets); + CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::pair opretWithId); CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::vector> oprets); int64_t AddCClibtxfee(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description); uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, std::vector> &oprets); -uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector> &oprets); + uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector &voutPubkeys, std::vector> &oprets); void GetNonfungibleData(uint256 tokenid, vscript_t &vopretNonfungible); bool ExtractTokensCCVinPubkeys(const CTransaction &tx, std::vector &vinPubkeys); @@ -293,6 +293,8 @@ void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uin bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen); UniValue ValueFromAmount(const CAmount& amount); +int64_t TotalPubkeyNormalInputs(const CTransaction &tx, const CPubKey &pubkey); +int64_t TotalPubkeyCCInputs(const CTransaction &tx, const CPubKey &pubkey); // bitcoin LogPrintStr with category "-debug" cmdarg support for C++ ostringstream: #define CCLOG_INFO 0 diff --git a/src/cc/CCtokens.cpp b/src/cc/CCtokens.cpp index a6ecf7123..be3cbd922 100644 --- a/src/cc/CCtokens.cpp +++ b/src/cc/CCtokens.cpp @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright © 2014-2018 The SuperNET Developers. * + * Copyright © 2014-2019 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * @@ -14,6 +14,7 @@ ******************************************************************************/ #include "CCtokens.h" +#include "importcoin.h" /* TODO: correct this: ----------------------------- @@ -102,22 +103,21 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & switch (funcid) { - case 'c': // create wont be called to be verified as it has no CC inputs + case 'c': // token create should not be validated as it has no CC inputs, so return 'invalid' + // token tx structure for 'c': //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; + return eval->Invalid("incorrect token funcid"); case 't': // transfer + // token tx structure for 't' //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 + //vout.n-1: opreturn EVAL_TOKENS 't' tokenid if (inputs == 0) return eval->Invalid("no token inputs for transfer"); @@ -129,20 +129,7 @@ bool TokensValidate(struct CCcontract_info *cp, Eval* eval, const CTransaction & return eval->Invalid("unexpected token funcid"); } - // 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; - - // 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)); } // helper funcs: @@ -333,7 +320,8 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true vscript_t vopretExtra, vopretNonfungible; std::vector> oprets; - uint8_t evalCode = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim + uint8_t evalCodeNonfungible = 0; + uint8_t evalCode1 = EVAL_TOKENS; // if both payloads are empty maybe it is a transfer to non-payload-one-eval-token vout like GatewaysClaim uint8_t evalCode2 = 0; // will be checked if zero or not // test vouts for possible token use-cases: @@ -354,12 +342,12 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true // non-fungible-eval -> EVAL_TOKENS -> assets-eval if (vopretNonfungible.size() > 0) - evalCode = vopretNonfungible.begin()[0]; + evalCodeNonfungible = evalCode1 = vopretNonfungible.begin()[0]; if (vopretExtra.size() > 0) evalCode2 = vopretExtra.begin()[0]; - if (evalCode == EVAL_TOKENS && evalCode2 != 0) { - evalCode = evalCode2; // for using MakeTokensCC1vout(evalcode,...) instead of MakeCC1vout(EVAL_TOKENS, evalcode...) + if (evalCode1 == EVAL_TOKENS && evalCode2 != 0) { + evalCode1 = evalCode2; // for using MakeTokensCC1vout(evalcode,...) instead of MakeCC1vout(EVAL_TOKENS, evalcode...) evalCode2 = 0; } @@ -369,39 +357,41 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true // maybe this is dual-eval 1 pubkey or 1of2 pubkey vout? if (voutPubkeys.size() >= 1 && voutPubkeys.size() <= 2) { // check dual/three-eval 1 pubkey vout with the first pubkey - testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0]")) ); + testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0]")) ); if (evalCode2 != 0) // also check in backward evalcode order - testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0] backward-eval")) ); + testVouts.push_back( std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[0]), std::string("three-eval cc1 pk[0] backward-eval")) ); if(voutPubkeys.size() == 2) { // check dual/three eval 1of2 pubkeys vout - testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2")) ); + testVouts.push_back( std::make_pair(MakeTokensCC1of2vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2")) ); // check dual/three eval 1 pubkey vout with the second pubkey - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1]"))); + testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1]"))); if (evalCode2 != 0) { // also check in backward evalcode order: // check dual/three eval 1of2 pubkeys vout - testVouts.push_back(std::make_pair(MakeTokensCC1of2vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2 backward-eval"))); + testVouts.push_back(std::make_pair(MakeTokensCC1of2vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[0], voutPubkeys[1]), std::string("three-eval cc1of2 backward-eval"))); // check dual/three eval 1 pubkey vout with the second pubkey - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1] backward-eval"))); + testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, voutPubkeys[1]), std::string("three-eval cc1 pk[1] backward-eval"))); } } + // maybe this is like gatewayclaim to single-eval token? + if( evalCodeNonfungible == 0 ) // do not allow to convert non-fungible to fungible token + testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]), std::string("single-eval cc1 pk[0]"))); - // maybe this is like gatewayclaim to single-eval token? - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[0]), std::string("single-eval cc1 pk[0]"))); // maybe this is like FillSell for non-fungible token? - if( evalCode != 0 ) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval-token cc1 pk[0]"))); + if( evalCode1 != 0 ) + testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval-token cc1 pk[0]"))); if( evalCode2 != 0 ) testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[0]), std::string("dual-eval2-token cc1 pk[0]"))); + // the same for pk[1]: if (voutPubkeys.size() == 2) { - // the same for pk[1]: - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]), std::string("single-eval cc1 pk[1]"))); - if (evalCode != 0) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval-token cc1 pk[1]"))); + if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token + testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, voutPubkeys[1]), std::string("single-eval cc1 pk[1]"))); + if (evalCode1 != 0) + testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval-token cc1 pk[1]"))); if (evalCode2 != 0) testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, tx.vout[v].nValue, voutPubkeys[1]), std::string("dual-eval2-token cc1 pk[1]"))); } @@ -413,52 +403,95 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys /*<--not used, always true FilterOutTokensUnspendablePk(vinPubkeysUnfiltered, vinPubkeys); // cannot send tokens to token unspendable cc addr (only marker is allowed there) for(std::vector::iterator it = vinPubkeys.begin(); it != vinPubkeys.end(); it++) { - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it), std::string("single-eval cc1 self vin pk"))); - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, evalCode2, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk"))); + if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token + testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, *it), std::string("single-eval cc1 self vin pk"))); + testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, evalCode2, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk"))); if (evalCode2 != 0) // also check in backward evalcode order: - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk backward-eval"))); + testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode2, evalCode1, tx.vout[v].nValue, *it), std::string("three-eval cc1 self vin pk backward-eval"))); } - } - else { - CPubKey origPubkey; - vscript_t vorigPubkey; - std::string dummyName, dummyDescription; - std::vector> oprets; - - if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, oprets) == 0) { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() could not decode create opret" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); - return 0; + // try all test vouts: + for (auto t : testVouts) { + if (t.first == tx.vout[v]) { // test vout matches + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() valid amount=" << tx.vout[v].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode1 << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl); + return tx.vout[v].nValue; + } } - origPubkey = pubkey2pk(vorigPubkey); - - // for 'c' recognize the tokens only to token originator pubkey (but not to unspendable <-- closed sec violation) - // maybe this is like gatewayclaim to single-eval token? - testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, origPubkey), std::string("single-eval cc1 orig-pk"))); - // maybe this is like FillSell for non-fungible token? - if (evalCode != 0) - testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode, tx.vout[v].nValue, origPubkey), std::string("dual-eval-token cc1 orig-pk"))); } + else { // funcid == 'c' + + if (!tx.IsCoinImport()) { - // try all test vouts: - for (auto t : testVouts) { - if (t.first == tx.vout[v]) { - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() valid amount=" << tx.vout[v].nValue << " msg=" << t.second << " evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " txid=" << tx.GetHash().GetHex() << " tokenid=" << reftokenid.GetHex() << std::endl); - return tx.vout[v].nValue; + vscript_t vorigPubkey; + std::string dummyName, dummyDescription; + std::vector> oprets; + + if (DecodeTokenCreateOpRet(tx.vout.back().scriptPubKey, vorigPubkey, dummyName, dummyDescription, oprets) == 0) { + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() could not decode create opret" << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); + return 0; + } + + CPubKey origPubkey = pubkey2pk(vorigPubkey); + + + // TODO: add voutPubkeys for 'c' tx + + /* this would not work for imported tokens: + // for 'c' recognize the tokens only to token originator pubkey (but not to unspendable <-- closed sec violation) + // maybe this is like gatewayclaim to single-eval token? + if (evalCodeNonfungible == 0) // do not allow to convert non-fungible to fungible token + testVouts.push_back(std::make_pair(MakeCC1vout(EVAL_TOKENS, tx.vout[v].nValue, origPubkey), std::string("single-eval cc1 orig-pk"))); + // maybe this is like FillSell for non-fungible token? + if (evalCode1 != 0) + testVouts.push_back(std::make_pair(MakeTokensCC1vout(evalCode1, tx.vout[v].nValue, origPubkey), std::string("dual-eval-token cc1 orig-pk"))); */ + + // note: this would not work if there are several pubkeys in the tokencreator's wallet (AddNormalinputs does not use pubkey param): + // for tokenbase tx check that normal inputs sent from origpubkey > cc outputs + int64_t ccOutputs = 0; + for (auto vout : tx.vout) + if (vout.scriptPubKey.IsPayToCryptoCondition() //TODO: add voutPubkey validation + && !IsTokenMarkerVout(vout)) // should not be marker here + ccOutputs += vout.nValue; + + int64_t normalInputs = TotalPubkeyNormalInputs(tx, origPubkey); // check if normal inputs are really signed by originator pubkey (someone not cheating with originator pubkey) + LOGSTREAM("cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() normalInputs=" << normalInputs << " ccOutputs=" << ccOutputs << " for tokenbase=" << reftokenid.GetHex() << std::endl); + + if (normalInputs >= ccOutputs) { + LOGSTREAM("cctokens", CCLOG_DEBUG2, stream << indentStr << "IsTokensvout() assured normalInputs >= ccOutputs" << " for tokenbase=" << reftokenid.GetHex() << std::endl); + if (!IsTokenMarkerVout(tx.vout[v])) // exclude marker + return tx.vout[v].nValue; + else + return 0; // vout is good, but do not take marker into account + } + else { + LOGSTREAM("cctokens", CCLOG_INFO, stream << indentStr << "IsTokensvout() skipping vout not fulfilled normalInputs >= ccOutput" << " for tokenbase=" << reftokenid.GetHex() << " normalInputs=" << normalInputs << " ccOutputs=" << ccOutputs << std::endl); + } } - } - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() no valid vouts evalCode=" << (int)evalCode << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); + else { + // imported tokens are checked in the eval::ImportCoin() validation code + if (!IsTokenMarkerVout(tx.vout[v])) // exclude marker + return tx.vout[v].nValue; + else + return 0; // vout is good, but do not take marker into account + } + } + LOGSTREAM("cctokens", CCLOG_DEBUG1, stream << indentStr << "IsTokensvout() no valid vouts evalCode=" << (int)evalCode1 << " evalCode2=" << (int)evalCode2 << " for txid=" << tx.GetHash().GetHex() << " for tokenid=" << reftokenid.GetHex() << std::endl); } - //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); } +bool IsTokenMarkerVout(CTxOut vout) { + struct CCcontract_info *cpTokens, CCtokens_info; + cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS); + return vout == MakeCC1vout(EVAL_TOKENS, vout.nValue, GetUnspendable(cpTokens, NULL)); +} + // compares cc inputs vs cc outputs (to prevent feeding vouts from normal inputs) bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cp, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 reftokenid) { @@ -582,6 +615,7 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C GetTokensCCaddress(cp, tokenaddr, pk); SetCCunspents(unspentOutputs, tokenaddr,true); + if (unspentOutputs.empty()) { LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "AddTokenCCInputs() no utxos for token dual/three eval addr=" << tokenaddr << " evalcode=" << (int)cp->evalcode << " additionalTokensEvalcode2=" << (int)cp->additionalTokensEvalcode2 << std::endl); } @@ -747,7 +781,7 @@ CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey) { return CPubKey(); //return invalid pubkey } - +// returns token creation signed raw tx std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, std::string description, vscript_t nonfungibleData) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); @@ -767,7 +801,7 @@ std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, st cp = CCinit(&C, EVAL_TOKENS); if (name.size() > 32 || description.size() > 4096) // this is also checked on rpc level { - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "name len=" << name.size() << " or description len=" << description.size() << " is too big" << std::endl); + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG1, stream << "name len=" << name.size() << " or description len=" << description.size() << " is too big" << std::endl); CCerror = "name should be <= 32, description should be <= 4096"; return(""); } @@ -777,6 +811,13 @@ std::string CreateToken(int64_t txfee, int64_t tokensupply, std::string name, st if (AddNormalinputs(mtx, mypk, tokensupply + 2 * txfee, 64) > 0) { + + int64_t mypkInputs = TotalPubkeyNormalInputs(mtx, mypk); + if (mypkInputs < tokensupply) { // check that tokens amount are really issued with mypk (because in the wallet there maybe other privkeys) + CCerror = "some inputs signed not with -pubkey=pk"; + return std::string(""); + } + uint8_t destEvalCode = EVAL_TOKENS; if( nonfungibleData.size() > 0 ) destEvalCode = nonfungibleData.begin()[0]; @@ -843,7 +884,7 @@ std::string TokenTransfer(int64_t txfee, uint256 tokenid, vscript_t destpubkey, } else { CCerror = strprintf("no token inputs"); - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << total << std::endl); + LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenTransfer() " << CCerror << " for amount=" << total << std::endl); } //} else fprintf(stderr,"numoutputs.%d != numamounts.%d\n",n,(int32_t)amounts.size()); } @@ -880,7 +921,7 @@ UniValue TokenInfo(uint256 tokenid) { UniValue result(UniValue::VOBJ); uint256 hashBlock; - CTransaction vintx; + CTransaction tokenbaseTx; std::vector origpubkey; std::vector> oprets; vscript_t vopretNonfungible; @@ -889,14 +930,14 @@ UniValue TokenInfo(uint256 tokenid) cpTokens = CCinit(&tokensCCinfo, EVAL_TOKENS); - if( !GetTransaction(tokenid, vintx, hashBlock, false) ) + if( !GetTransaction(tokenid, tokenbaseTx, hashBlock, false) ) { fprintf(stderr, "TokenInfo() cant find tokenid\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, oprets) != 'c') + if (tokenbaseTx.vout.size() > 0 && DecodeTokenCreateOpRet(tokenbaseTx.vout[tokenbaseTx.vout.size() - 1].scriptPubKey, origpubkey, name, description, oprets) != 'c') { LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "TokenInfo() passed tokenid isnt token creation txid" << std::endl); result.push_back(Pair("result", "error")); @@ -909,8 +950,8 @@ UniValue TokenInfo(uint256 tokenid) result.push_back(Pair("name", name)); int64_t supply = 0, output; - for (int v = 0; v < vintx.vout.size() - 1; v++) - if ((output = IsTokensvout(false, true, cpTokens, NULL, vintx, v, tokenid)) > 0) + for (int v = 0; v < tokenbaseTx.vout.size() - 1; v++) + if ((output = IsTokensvout(false, true, cpTokens, NULL, tokenbaseTx, v, tokenid)) > 0) supply += output; result.push_back(Pair("supply", supply)); result.push_back(Pair("description", description)); @@ -919,6 +960,40 @@ UniValue TokenInfo(uint256 tokenid) if( !vopretNonfungible.empty() ) result.push_back(Pair("data", HexStr(vopretNonfungible))); + if (tokenbaseTx.IsCoinImport()) { // if imported token + ImportProof proof; + CTransaction burnTx; + std::vector payouts; + CTxDestination importaddress; + + std::string sourceSymbol = "can't decode"; + std::string sourceTokenId = "can't decode"; + + if (UnmarshalImportTx(tokenbaseTx, proof, burnTx, payouts)) + { + // extract op_return to get burn source chain. + std::vector burnOpret; + std::string targetSymbol; + uint32_t targetCCid; + uint256 payoutsHash; + std::vector rawproof; + if (UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) { + if (rawproof.size() > 0) { + CTransaction tokenbasetx; + E_UNMARSHAL(rawproof, ss >> sourceSymbol; + if (!ss.eof()) + ss >> tokenbasetx); + + if (!tokenbasetx.IsNull()) + sourceTokenId = tokenbasetx.GetHash().GetHex(); + } + } + } + result.push_back(Pair("IsImported", "yes")); + result.push_back(Pair("sourceChain", sourceSymbol)); + result.push_back(Pair("sourceTokenId", sourceTokenId)); + } + return result; } diff --git a/src/cc/CCtokens.h b/src/cc/CCtokens.h index f63c563a9..3705a8f6d 100644 --- a/src/cc/CCtokens.h +++ b/src/cc/CCtokens.h @@ -32,6 +32,7 @@ std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, st std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector destpubkey, int64_t total); int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, uint256 reftokenid); CPubKey GetTokenOriginatorPubKey(CScript scriptPubKey); +bool IsTokenMarkerVout(CTxOut vout); int64_t GetTokenBalance(CPubKey pk, uint256 tokenid); UniValue TokenInfo(uint256 tokenid); diff --git a/src/cc/CCtokensOpRet.cpp b/src/cc/CCtokenutils.cpp similarity index 69% rename from src/cc/CCtokensOpRet.cpp rename to src/cc/CCtokenutils.cpp index 4c6dc4b6d..73209bcb5 100644 --- a/src/cc/CCtokensOpRet.cpp +++ b/src/cc/CCtokenutils.cpp @@ -1,5 +1,21 @@ +/****************************************************************************** +* Copyright © 2014-2019 The SuperNET Developers. * +* * +* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * +* the top-level directory of this distribution for the individual copyright * +* holder information and the developer policies on copyright and licensing. * +* * +* Unless otherwise agreed in a custom licensing agreement, no part of the * +* SuperNET software, including this file may be copied, modified, propagated * +* or distributed except according to the terms contained in the LICENSE file * +* * +* Removal or modification of this copyright notice is prohibited. * +* * +******************************************************************************/ + // encode decode tokens opret -// (moved to a separate file to enable linking lib common.so with importcoin.cpp) +// make token cryptoconditions and vouts +// This code was moved to a separate source file to enable linking libcommon.so (with importcoin.cpp which depends on some token functions) #include "CCtokens.h" @@ -44,6 +60,7 @@ CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, return(opret); } +/* // opret 'i' for imported tokens CScript EncodeTokenImportOpRet(std::vector origpubkey, std::string name, std::string description, uint256 srctokenid, std::vector> oprets) { @@ -62,7 +79,7 @@ CScript EncodeTokenImportOpRet(std::vector origpubkey, std::string name }); return(opret); } - +*/ CScript EncodeTokenOpRet(uint256 tokenid, std::vector voutPubkeys, std::pair opretWithId) @@ -158,37 +175,9 @@ uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector return (uint8_t)0; } -// for imported tokens -uint8_t DecodeTokenImportOpRet(const CScript &scriptPubKey, std::vector &origpubkey, std::string &name, std::string &description, uint256 &srctokenid, std::vector> &oprets) -{ - vscript_t vopret, vblob; - uint8_t dummyEvalcode, funcid, opretId = 0; - - GetOpReturnData(scriptPubKey, vopret); - oprets.clear(); - - if (vopret.size() > 2 && vopret.begin()[0] == EVAL_TOKENS && vopret.begin()[1] == 'i') - { - if (E_UNMARSHAL(vopret, ss >> dummyEvalcode; ss >> funcid; ss >> origpubkey; ss >> name; ss >> description; ss >> srctokenid; - while (!ss.eof()) { - ss >> opretId; - if (!ss.eof()) { - ss >> vblob; - oprets.push_back(std::make_pair(opretId, vblob)); - } - })) - { - srctokenid = revuint256(srctokenid); // do not forget this - return(funcid); - } - } - LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenImportOpRet() incorrect token import opret" << std::endl); - return (uint8_t)0; -} - -// decodes token opret: +// decode token opret: // for 't' returns all data from opret, vopretExtra contains other contract's data (currently only assets'). -// for 'c' and 'i' returns only funcid. NOTE: nonfungible data is not returned +// for 'c' returns only funcid. NOTE: nonfungible data is not returned uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector &voutPubkeys, std::vector> &oprets) { vscript_t vopret, vblob, dummyPubkey, vnonfungibleDummy; @@ -207,9 +196,6 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, ui if (script != NULL && 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; - evalCodeTokens = script[0]; if (evalCodeTokens != EVAL_TOKENS) { LOGSTREAM((char *)"cctokens", CCLOG_INFO, stream << "DecodeTokenOpRet() incorrect evalcode in tokens opret" << std::endl); @@ -217,15 +203,13 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, ui } funcId = script[1]; - LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet decoded funcId=" << (char)(funcId ? funcId : ' ') << std::endl); + LOGSTREAM((char *)"cctokens", CCLOG_DEBUG2, stream << "DecodeTokenOpRet() decoded funcId=" << (char)(funcId ? funcId : ' ') << std::endl); switch (funcId) { case 'c': return DecodeTokenCreateOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, oprets); - case 'i': - return DecodeTokenImportOpRet(scriptPubKey, dummyPubkey, dummyName, dummyDescription, dummySrcTokenId, oprets); - //break; + case 't': // compatibility with old-style rogue or assets data (with no opretid): @@ -293,4 +277,75 @@ uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, ui } +// make three-eval (token+evalcode+evalcode2) 1of2 cryptocondition: +CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2) +{ + // make 1of2 sigs cond + std::vector pks; + pks.push_back(CCNewSecp256k1(pk1)); + pks.push_back(CCNewSecp256k1(pk2)); + + 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 + if (evalcode2 != 0) + thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode + thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc + + return CCNewThreshold(thresholds.size(), thresholds); +} +// overload to make two-eval (token+evalcode) 1of2 cryptocondition: +CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) { + return MakeTokensCCcond1of2(evalcode, 0, pk1, pk2); +} + +// make three-eval (token+evalcode+evalcode2) cryptocondition: +CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk) +{ + std::vector pks; + pks.push_back(CCNewSecp256k1(pk)); + + 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 + if (evalcode2 != 0) + thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode + thresholds.push_back(CCNewThreshold(1, pks)); // signature + + return CCNewThreshold(thresholds.size(), thresholds); +} +// overload to make two-eval (token+evalcode) cryptocondition: +CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) { + return MakeTokensCCcond1(evalcode, 0, pk); +} + +// make three-eval (token+evalcode+evalcode2) 1of2 cc vout: +CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2) +{ + CTxOut vout; + CC *payoutCond = MakeTokensCCcond1of2(evalcode, evalcode2, pk1, pk2); + vout = CTxOut(nValue, CCPubKey(payoutCond)); + cc_free(payoutCond); + return(vout); +} +// overload to make two-eval (token+evalcode) 1of2 cc vout: +CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) { + return MakeTokensCC1of2vout(evalcode, 0, nValue, pk1, pk2); +} + +// make three-eval (token+evalcode+evalcode2) cc vout: +CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk) +{ + CTxOut vout; + CC *payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk); + vout = CTxOut(nValue, CCPubKey(payoutCond)); + cc_free(payoutCond); + return(vout); +} +// overload to make two-eval (token+evalcode) cc vout: +CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) { + return MakeTokensCC1vout(evalcode, 0, nValue, pk); +} diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index a34bf1a81..e9acfbe20 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -93,79 +93,6 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, c return(vout); } -// make three-eval (token+evalcode+evalcode2) 1of2 cryptocondition: -CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2) -{ - // make 1of2 sigs cond - std::vector pks; - pks.push_back(CCNewSecp256k1(pk1)); - pks.push_back(CCNewSecp256k1(pk2)); - - 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 - if( evalcode2 != 0 ) - thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode - thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc - - return CCNewThreshold(thresholds.size(), thresholds); -} -// overload to make two-eval (token+evalcode) 1of2 cryptocondition: -CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) { - return MakeTokensCCcond1of2(evalcode, 0, pk1, pk2); -} - -// make three-eval (token+evalcode+evalcode2) cryptocondition: -CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk) -{ - std::vector pks; - pks.push_back(CCNewSecp256k1(pk)); - - 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 - if (evalcode2 != 0) - thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode - thresholds.push_back(CCNewThreshold(1, pks)); // signature - - return CCNewThreshold(thresholds.size(), thresholds); -} -// overload to make two-eval (token+evalcode) cryptocondition: -CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) { - return MakeTokensCCcond1(evalcode, 0, pk); -} - -// make three-eval (token+evalcode+evalcode2) 1of2 cc vout: -CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2) -{ - CTxOut vout; - CC *payoutCond = MakeTokensCCcond1of2(evalcode, evalcode2, pk1, pk2); - vout = CTxOut(nValue, CCPubKey(payoutCond)); - cc_free(payoutCond); - return(vout); -} -// overload to make two-eval (token+evalcode) 1of2 cc vout: -CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) { - return MakeTokensCC1of2vout(evalcode, 0, nValue, pk1, pk2); -} - -// make three-eval (token+evalcode+evalcode2) cc vout: -CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk) -{ - CTxOut vout; - CC *payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk); - vout = CTxOut(nValue, CCPubKey(payoutCond)); - cc_free(payoutCond); - return(vout); -} -// overload to make two-eval (token+evalcode) cc vout: -CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) { - return MakeTokensCC1vout(evalcode, 0, nValue, pk); -} - - CC* GetCryptoCondition(CScript const& scriptSig) { auto pc = scriptSig.begin(); @@ -709,6 +636,57 @@ CPubKey check_signing_pubkey(CScript scriptSig) return CPubKey(); } + +// returns total of normal inputs signed with this pubkey +int64_t TotalPubkeyNormalInputs(const CTransaction &tx, const CPubKey &pubkey) +{ + int64_t total = 0; + for (auto vin : tx.vin) { + CTransaction vintx; + uint256 hashBlock; + if (!IsCCInput(vin.scriptSig) && myGetTransaction(vin.prevout.hash, vintx, hashBlock)) { + typedef std::vector valtype; + std::vector vSolutions; + txnouttype whichType; + + if (Solver(vintx.vout[vin.prevout.n].scriptPubKey, whichType, vSolutions)) { + switch (whichType) { + case TX_PUBKEY: + if (pubkey == CPubKey(vSolutions[0])) // is my input? + total += vintx.vout[vin.prevout.n].nValue; + break; + case TX_PUBKEYHASH: + if (pubkey.GetID() == CKeyID(uint160(vSolutions[0]))) // is my input? + total += vintx.vout[vin.prevout.n].nValue; + break; + } + } + } + } + return total; +} + +// returns total of CC inputs signed with this pubkey +int64_t TotalPubkeyCCInputs(const CTransaction &tx, const CPubKey &pubkey) +{ + int64_t total = 0; + for (auto vin : tx.vin) { + if (IsCCInput(vin.scriptSig)) { + CPubKey vinPubkey = check_signing_pubkey(vin.scriptSig); + if (vinPubkey.IsValid()) { + if (vinPubkey == pubkey) { + CTransaction vintx; + uint256 hashBlock; + if (myGetTransaction(vin.prevout.hash, vintx, hashBlock)) { + total += vintx.vout[vin.prevout.n].nValue; + } + } + } + } + } + return total; +} + bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector paramsNull,const CTransaction &ctx, unsigned int nIn) { CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector origpubkey; diff --git a/src/cc/import.cpp b/src/cc/import.cpp index ea22f5e42..45dd16732 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -20,9 +20,18 @@ #include "primitives/transaction.h" #include "cc/CCinclude.h" #include +#include "cc/CCtokens.h" #include "key_io.h" #define CODA_BURN_ADDRESS "KPrrRoPfHOnNpZZQ6laHXdQDkSQDkVHaN0V+LizLlHxz7NaA59sBAAAA" +/* + * CC Eval method for import coin. + * + * This method should control every parameter of the ImportCoin transaction, since it has no signature + * to protect it from malleability. + + ##### 0xffffffff is a special CCid for single chain/dual daemon imports + */ extern std::string ASSETCHAINS_SELFIMPORT; extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT; @@ -60,64 +69,65 @@ cJSON* CodaRPC(char **retstr,char const *arg0,char const *arg1,char const *arg2, } // makes source tx for self import tx -std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx) +CMutableTransaction MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount) { const int64_t txfee = 10000; int64_t inputs, change; CPubKey myPubKey = Mypubkey(); struct CCcontract_info *cpDummy, C; - cpDummy = CCinit(&C, EVAL_TOKENS); + cpDummy = CCinit(&C, EVAL_TOKENS); // this is just for FinalizeCCTx to work - mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - if( (inputs = AddNormalinputs(mtx, myPubKey, txfee, 4)) == 0 ) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx: cannot find normal imputs for txfee" << std::endl); - return std::string(""); + if (AddNormalinputs(mtx, myPubKey, 2 * txfee, 4) == 0) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx() warning: cannot find normal inputs for txfee" << std::endl); } - + CScript scriptPubKey = GetScriptForDestination(dest); mtx.vout.push_back(CTxOut(txfee, scriptPubKey)); - change = inputs - txfee; - if( change != 0 ) - mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG)); - //make opret with amount: - return FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount)); + //make opret with 'burned' amount: + FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount)); + return mtx; } -// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33 -int32_t CheckVin0PubKey(const CTransaction &sourcetx) +// make sure vin is signed by pubkey33 +bool CheckVinPubKey(const CTransaction &sourcetx, int32_t i, uint8_t pubkey33[33]) { CTransaction vintx; uint256 blockHash; char destaddr[64], pkaddr[64]; - if( !myGetTransaction(sourcetx.vin[0].prevout.hash, vintx, blockHash) ) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() could not load vintx" << sourcetx.vin[0].prevout.hash.GetHex() << std::endl); - return(-1); + if (i < 0 || i >= sourcetx.vin.size()) + return false; + + if( !myGetTransaction(sourcetx.vin[i].prevout.hash, vintx, blockHash) ) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVinPubKey() could not load vintx" << sourcetx.vin[i].prevout.hash.GetHex() << std::endl); + return false; } - if( sourcetx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[0].prevout.n].scriptPubKey) != 0 ) + if( sourcetx.vin[i].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[i].prevout.n].scriptPubKey) != 0 ) { - pubkey2addr(pkaddr, ASSETCHAINS_OVERRIDE_PUBKEY33); + pubkey2addr(pkaddr, pubkey33); if (strcmp(pkaddr, destaddr) == 0) { - return(0); + return true; } - LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() mismatched vin0[prevout.n=" << sourcetx.vin[0].prevout.n << "] -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl); + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVinPubKey() mismatched vin[" << i << "].prevout.n=" << sourcetx.vin[i].prevout.n << " -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl); } - return -1; + return false; } // ac_import=PUBKEY support: // prepare a tx for creating import tx and quasi-burn tx -int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount) // find burnTx with hash from "other" daemon +int32_t GetSelfimportProof(const CMutableTransaction &sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull) // find burnTx with hash from "other" daemon { MerkleBranch newBranch; CMutableTransaction tmpmtx; - CTransaction sourcetx; + //CTransaction sourcetx; tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + /* if (!E_UNMARSHAL(ParseHex(rawsourcetx), ss >> sourcetx)) { LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: could not unmarshal source tx" << std::endl); return(-1); @@ -126,9 +136,9 @@ int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript if (sourcetx.vout.size() == 0) { LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: vout size is 0" << std::endl); return -1; - } + } */ - if (ivout < 0) { // "ivout < 0" means "find" + /*if (ivout < 0) { // "ivout < 0" means "find" // try to find vout CPubKey myPubkey = Mypubkey(); ivout = 0; @@ -140,38 +150,49 @@ int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript if (ivout >= sourcetx.vout.size()) { LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: needed vout not found" << std::endl); return -1; - } + } */ - LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl); + int32_t ivout = 0; - scriptPubKey = sourcetx.vout[ivout].scriptPubKey; + // LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl); + + CScript scriptPubKey = sourceMtx.vout[ivout].scriptPubKey; //mtx is template for import tx - mtx = sourcetx; - mtx.fOverwintered = tmpmtx.fOverwintered; + templateMtx = sourceMtx; + templateMtx.fOverwintered = tmpmtx.fOverwintered; //malleability fix for burn tx: //mtx.nExpiryHeight = tmpmtx.nExpiryHeight; - mtx.nExpiryHeight = sourcetx.nExpiryHeight; + templateMtx.nExpiryHeight = sourceMtx.nExpiryHeight; - mtx.nVersionGroupId = tmpmtx.nVersionGroupId; - mtx.nVersion = tmpmtx.nVersion; - mtx.vout.clear(); - mtx.vout.resize(1); - mtx.vout[0].nValue = burnAmount; - mtx.vout[0].scriptPubKey = scriptPubKey; + templateMtx.nVersionGroupId = tmpmtx.nVersionGroupId; + templateMtx.nVersion = tmpmtx.nVersion; + templateMtx.vout.clear(); + templateMtx.vout.resize(1); - // not sure we need this now as we create sourcetx ourselves: - if (sourcetx.GetHash() != sourcetxid) { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl); - return(-1); - } - - // check ac_pubkey: - if (CheckVin0PubKey(sourcetx) < 0) { + uint8_t evalCode, funcId; + int64_t burnAmount; + vscript_t vopret; + if( !GetOpReturnData(sourceMtx.vout.back().scriptPubKey, vopret) || + !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> burnAmount)) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof() could not unmarshal source tx opret" << std::endl); return -1; } - proof = std::make_pair(sourcetxid, newBranch); + templateMtx.vout[0].nValue = burnAmount; + templateMtx.vout[0].scriptPubKey = scriptPubKey; + + // not sure we need this now as we create sourcetx ourselves: + /*if (sourcetx.GetHash() != sourcetxid) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl); + return(-1); + }*/ + + // check ac_pubkey: + if (!CheckVinPubKey(sourceMtx, 0, ASSETCHAINS_OVERRIDE_PUBKEY33)) { + return -1; + } + proofNull = ImportProof(std::make_pair(sourceMtx.GetHash(), newBranch)); return 0; } @@ -470,7 +491,7 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti } //ac_pubkey check: - if (CheckVin0PubKey(sourcetx) < 0) { + if (!CheckVinPubKey(sourcetx, 0, ASSETCHAINS_OVERRIDE_PUBKEY33)) { return -1; } @@ -479,9 +500,11 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti uint8_t evalCode, funcId; int64_t amount; - GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret); - if (vopret.size() == 0 || !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || evalCode != EVAL_IMPORTCOIN || funcId != 'A') { - LOGSTREAM("importcoin", CCLOG_INFO, stream << "no or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl); + if (!GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret) || + vopret.size() == 0 || + !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || + evalCode != EVAL_IMPORTCOIN || funcId != 'A') { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "none or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl); return -1; } @@ -496,21 +519,149 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti return(0); } -/* - * CC Eval method for import coin. - * - * This method should control every parameter of the ImportCoin transaction, since it has no signature - * to protect it from malleability. - - ##### 0xffffffff is a special CCid for single chain/dual daemon imports - */ -bool Eval::ImportCoin(const std::vector params,const CTransaction &importTx,unsigned int nIn) +bool CheckFungible(Eval *eval, const CTransaction &importTx, const CTransaction &burnTx, std::vector & payouts, const ImportProof &proof, const std::vector &rawproof) { - TxProof proof; CTransaction burnTx; std::vector payouts; int64_t txfee = 10000, amount; int32_t height,burnvout; std::vector publishers; - uint32_t targetCcid; std::string targetSymbol,srcaddr,destaddr,receipt,rawburntx; uint256 payoutsHash,bindtxid,burntxid; std::vector rawproof; - std::vector txids; CPubKey destpub; + if (strcmp(ASSETCHAINS_SYMBOL, "CFEKDIMXY6") == 0 && chainActive.Height() <= 10699) + return true; - if ( importTx.vout.size() < 2 ) + vscript_t vimportOpret; + if (!GetOpReturnData(importTx.vout.back().scriptPubKey, vimportOpret) || + vimportOpret.empty()) + return eval->Invalid("invalid-import-tx-no-opret"); + + + uint256 tokenid = zeroid; + if (vimportOpret.begin()[0] == EVAL_TOKENS) { // for tokens (new opret with tokens) + struct CCcontract_info *cpTokens, CCtokens_info; + std::vector> oprets; + uint8_t evalCodeInOpret; + std::vector voutTokenPubkeys; + vscript_t vnonfungibleOpret; + + cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS); + + if (DecodeTokenOpRet(importTx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) == 0) + return eval->Invalid("cannot-decode-import-tx-token-opret"); + + uint8_t nonfungibleEvalCode = EVAL_TOKENS; // init to no non-fungibles + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vnonfungibleOpret); + if (!vnonfungibleOpret.empty()) + nonfungibleEvalCode = vnonfungibleOpret.begin()[0]; + + // check if burn tx at least has cc evaltoken vins (we cannot get cc input) + bool hasTokenVin = false; + for (auto vin : burnTx.vin) + if (cpTokens->ismyvin(vin.scriptSig)) + hasTokenVin = true; + if (!hasTokenVin) + return eval->Invalid("burn-tx-has-no-token-vins"); + + // calc outputs for burn tx + CAmount ccBurnOutputs = 0; + for (auto v : burnTx.vout) + if (v.scriptPubKey.IsPayToCryptoCondition() && + CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(nonfungibleEvalCode, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey + ccBurnOutputs += v.nValue; + + // calc outputs for import tx + CAmount ccImportOutputs = 0; + for (auto v : importTx.vout) + if (v.scriptPubKey.IsPayToCryptoCondition() && + !IsTokenMarkerVout(v)) // should not be marker here + ccImportOutputs += v.nValue; + + if (ccBurnOutputs != ccImportOutputs) + return eval->Invalid("token-cc-burned-output-not-equal-cc-imported-output"); + + } + else if (vimportOpret.begin()[0] != EVAL_IMPORTCOIN) { + return eval->Invalid("import-tx-incorrect-opret-eval"); + } + + // for tokens check burn, import, tokenbase tx + if (!tokenid.IsNull()) { + + std::string sourceSymbol; + CTransaction tokenbaseTx; + if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol; ss >> tokenbaseTx)) + return eval->Invalid("cannot-unmarshal-rawproof-for-tokens"); + + uint256 sourceTokenId; + std::vector> oprets; + uint8_t evalCodeInOpret; + std::vector voutTokenPubkeys; + if (burnTx.vout.size() > 0 && DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCodeInOpret, sourceTokenId, voutTokenPubkeys, oprets) == 0) + return eval->Invalid("cannot-decode-burn-tx-token-opret"); + + if (sourceTokenId != tokenbaseTx.GetHash()) // check tokenid in burn tx opret maches the passed tokenbase tx (to prevent cheating by importing user) + return eval->Invalid("incorrect-token-creation-tx-passed"); + + std::vector> opretsSrc; + vscript_t vorigpubkeySrc; + std::string nameSrc, descSrc; + if (DecodeTokenCreateOpRet(tokenbaseTx.vout.back().scriptPubKey, vorigpubkeySrc, nameSrc, descSrc, opretsSrc) == 0) + return eval->Invalid("cannot-decode-token-creation-tx"); + + std::vector> opretsImport; + vscript_t vorigpubkeyImport; + std::string nameImport, descImport; + if (importTx.vout.size() == 0 || DecodeTokenCreateOpRet(importTx.vout.back().scriptPubKey, vorigpubkeySrc, nameSrc, descSrc, opretsImport) == 0) + return eval->Invalid("cannot-decode-token-import-tx"); + + // check that name,pubkey,description in import tx correspond ones in token creation tx in the source chain: + if (vorigpubkeySrc != vorigpubkeyImport || + nameSrc != nameImport || + descSrc != descImport) + return eval->Invalid("import-tx-token-params-incorrect"); + } + + + // Check burntx shows correct outputs hash +// if (payoutsHash != SerializeHash(payouts)) // done in ImportCoin +// return eval->Invalid("wrong-payouts"); + + + TxProof merkleBranchProof; + std::vector notaryTxids; + + // Check proof confirms existance of burnTx + if (proof.IsMerkleBranch(merkleBranchProof)) { + uint256 target = merkleBranchProof.second.Exec(burnTx.GetHash()); + LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "Eval::ImportCoin() momom target=" << target.GetHex() << " merkleBranchProof.first=" << merkleBranchProof.first.GetHex() << std::endl); + if (!CheckMoMoM(merkleBranchProof.first, target)) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MoMoM check failed for importtx=" << importTx.GetHash().GetHex() << std::endl); + return eval->Invalid("momom-check-fail"); + } + } + else if (proof.IsNotaryTxids(notaryTxids)) { + if (!CheckNotariesApproval(burnTx.GetHash(), notaryTxids)) { + return eval->Invalid("notaries-approval-check-fail"); + } + } + else { + return eval->Invalid("invalid-import-proof"); + } + return true; +} + +bool Eval::ImportCoin(const std::vector params, const CTransaction &importTx, unsigned int nIn) +{ + ImportProof proof; + CTransaction burnTx; + std::vector payouts; + CAmount txfee = 10000; + int32_t height, burnvout; + std::vector publishers; + uint32_t targetCcid; + std::string targetSymbol, srcaddr, destaddr, receipt, rawburntx; + uint256 payoutsHash, bindtxid; + std::vector rawproof; + std::vector txids; + CPubKey destpub; + + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "Validating import tx..., txid=" << importTx.GetHash().GetHex() << std::endl); + + if (importTx.vout.size() < 2) return Invalid("too-few-vouts"); // params if (!UnmarshalImportTx(importTx, proof, burnTx, payouts)) @@ -522,38 +673,47 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo // burn params if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof)) return Invalid("invalid-burn-tx"); - // check burn amount - { - uint64_t burnAmount = burnTx.vout.back().nValue; - if (burnAmount == 0) - return Invalid("invalid-burn-amount"); - uint64_t totalOut = 0; - for (int i=0; i burnAmount || totalOut < burnAmount-txfee ) - return Invalid("payout-too-high-or-too-low"); - } + + if (burnTx.vout.size() == 0) + return Invalid("invalid-burn-tx-no-vouts"); + + // check burned normal amount >= import amount && burned amount <= import amount + txfee (extra txfee is for miners and relaying, see GetImportCoinValue() func) + CAmount burnAmount = burnTx.vout.back().nValue; + if (burnAmount == 0) + return Invalid("invalid-burn-amount"); + CAmount totalOut = 0; + for (auto v : importTx.vout) + if (!v.scriptPubKey.IsPayToCryptoCondition()) + totalOut += v.nValue; + if (totalOut > burnAmount || totalOut < burnAmount - txfee) + return Invalid("payout-too-high-or-too-low"); + // Check burntx shows correct outputs hash if (payoutsHash != SerializeHash(payouts)) return Invalid("wrong-payouts"); if (targetCcid < KOMODO_FIRSTFUNGIBLEID) return Invalid("chain-not-fungible"); - // Check proof confirms existance of burnTx + if ( targetCcid != 0xffffffff ) { - if ( targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol() ) + + if (targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol()) return Invalid("importcoin-wrong-chain"); - uint256 target = proof.second.Exec(burnTx.GetHash()); - if (!CheckMoMoM(proof.first, target)) - return Invalid("momom-check-fail"); + + if (!CheckFungible(this, importTx, burnTx, payouts, proof, rawproof)) + return false; } else { + TxProof merkleBranchProof; + if (!proof.IsMerkleBranch(merkleBranchProof)) + return Invalid("invalid-import-proof-for-0xFFFFFFFF"); + if ( targetSymbol == "BEAM" ) { if ( ASSETCHAINS_BEAMPORT == 0 ) return Invalid("BEAM-import-without-port"); - else if ( CheckBEAMimport(proof,rawproof,burnTx,payouts) < 0 ) + else if ( CheckBEAMimport(merkleBranchProof,rawproof,burnTx,payouts) < 0 ) return Invalid("BEAM-import-failure"); } else if ( targetSymbol == "CODA" ) @@ -567,7 +727,7 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo { if ( ASSETCHAINS_SELFIMPORT != "PUBKEY" ) return Invalid("PUBKEY-import-when-notPUBKEY"); - else if ( CheckPUBKEYimport(proof,rawproof,burnTx,payouts) < 0 ) + else if ( CheckPUBKEYimport(merkleBranchProof,rawproof,burnTx,payouts) < 0 ) return Invalid("PUBKEY-import-failure"); } else @@ -578,5 +738,14 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo return Invalid("GATEWAY-import-failure"); } } + + // return Invalid("test-invalid"); + LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "Valid import tx! txid=" << importTx.GetHash().GetHex() << std::endl); + + /*if (vimportOpret.begin()[0] == EVAL_TOKENS) + return Invalid("test-invalid-tokens-are-good!!"); + else + return Invalid("test-invalid-coins-are-good!!");*/ + return Valid(); } diff --git a/src/crosschain.cpp b/src/crosschain.cpp index 82a46eaab..0a081c086 100644 --- a/src/crosschain.cpp +++ b/src/crosschain.cpp @@ -18,6 +18,9 @@ #include "importcoin.h" #include "main.h" #include "notarisationdb.h" +#include "merkleblock.h" + +#include "cc/CCinclude.h" /* * The crosschain workflow. @@ -229,22 +232,25 @@ cont: */ void CompleteImportTransaction(CTransaction &importTx, int32_t offset) { - TxProof proof; CTransaction burnTx; std::vector payouts; std::vector rawproof; + ImportProof proof; CTransaction burnTx; std::vector payouts; std::vector rawproof; if (!UnmarshalImportTx(importTx, proof, burnTx, payouts)) - throw std::runtime_error("Couldn't parse importTx"); + throw std::runtime_error("Couldn't unmarshal importTx"); std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) - throw std::runtime_error("Couldn't parse burnTx"); + throw std::runtime_error("Couldn't unmarshal burnTx"); - proof = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, proof, offset); + TxProof merkleBranch; + if( !proof.IsMerkleBranch(merkleBranch) ) + throw std::runtime_error("Incorrect import tx proof"); + TxProof newMerkleBranch = GetCrossChainProof(burnTx.GetHash(), targetSymbol.data(), targetCCid, merkleBranch, offset); + ImportProof newProof(newMerkleBranch); - importTx = MakeImportCoinTransaction(proof, burnTx, payouts); + importTx = MakeImportCoinTransaction(newProof, burnTx, payouts); } - bool IsSameAssetChain(const Notarisation ¬a) { return strcmp(nota.second.symbol, ASSETCHAINS_SYMBOL) == 0; }; @@ -306,6 +312,111 @@ bool CheckMoMoM(uint256 kmdNotarisationHash, uint256 momom) } +/* +* Check notaries approvals for the txoutproofs of burn tx +* (alternate check if MoMoM check has failed) +* Params: +* burntxid - txid of burn tx on the source chain +* rawproof - array of txids of notaries' proofs +*/ +bool CheckNotariesApproval(uint256 burntxid, const std::vector & notaryTxids) +{ + int count = 0; + + // get notaries: + uint8_t notaries_pubkeys[64][33]; + std::vector< std::vector > alreadySigned; + + //unmarshal notaries approval txids + for(auto notarytxid : notaryTxids ) { + EvalRef eval; + CBlockIndex block; + CTransaction notarytx; // tx with notary approval of txproof existence + + // get notary approval tx + if (eval->GetTxConfirmed(notarytxid, notarytx, block)) { + + std::vector vopret; + if (!notarytx.vout.empty() && GetOpReturnData(notarytx.vout.back().scriptPubKey, vopret)) { + std::vector txoutproof; + + if (E_UNMARSHAL(vopret, ss >> txoutproof)) { + CMerkleBlock merkleBlock; + std::vector prooftxids; + // extract block's merkle tree + if (E_UNMARSHAL(txoutproof, ss >> merkleBlock)) { + + // extract proven txids: + merkleBlock.txn.ExtractMatches(prooftxids); + if (merkleBlock.txn.ExtractMatches(prooftxids) != merkleBlock.header.hashMerkleRoot || // check block merkle root is correct + std::find(prooftxids.begin(), prooftxids.end(), burntxid) != prooftxids.end()) { // check burn txid is in proven txids list + + if (komodo_notaries(notaries_pubkeys, block.GetHeight(), block.GetBlockTime()) >= 0) { + // check it is a notary who signed approved tx: + int i; + for (i = 0; i < sizeof(notaries_pubkeys) / sizeof(notaries_pubkeys[0]); i++) { + std::vector vnotarypubkey(notaries_pubkeys[i], notaries_pubkeys[i] + 33); +#ifdef TESTMODE + char test_notary_pubkey_hex[] = "029fa302968bbae81f41983d2ec20445557b889d31227caec5d910d19b7510ef86"; + uint8_t test_notary_pubkey33[33]; + decode_hex(test_notary_pubkey33, 33, test_notary_pubkey_hex); +#endif + if (CheckVinPubKey(notarytx, 0, notaries_pubkeys[i]) // is signed by a notary? + && std::find(alreadySigned.begin(), alreadySigned.end(), vnotarypubkey) == alreadySigned.end() // check if notary not re-used +#ifdef TESTMODE + || CheckVinPubKey(notarytx, 0, test_notary_pubkey33) // test +#endif + ) + { + alreadySigned.push_back(vnotarypubkey); + count++; + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "CheckNotariesApproval() notary approval checked, count=" << count << std::endl); + break; + } + } + if (i == sizeof(notaries_pubkeys) / sizeof(notaries_pubkeys[0])) + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "CheckNotariesApproval() txproof not signed by a notary or reused" << std::endl); + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() cannot get current notaries pubkeys" << std::endl); + } + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() burntxid not found in txoutproof or incorrect txoutproof" << std::endl); + } + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not unmarshal merkleBlock" << std::endl); + } + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not unmarshal txoutproof" << std::endl); + } + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() no opret in the notary tx" << std::endl); + } + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() could not load notary tx" << std::endl); + } + } + + bool retcode; +#ifdef TESTMODE + if (count < 1) { // 1 for test +#else + if (count < 5) { +#endif + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckNotariesApproval() not enough signed notary transactions=" << count << std::endl); + retcode = false; + } + else + retcode = true; + + return retcode; +} + /* * On assetchain diff --git a/src/crosschain.h b/src/crosschain.h index 9ff41eff1..25763c01b 100644 --- a/src/crosschain.h +++ b/src/crosschain.h @@ -43,6 +43,6 @@ void CompleteImportTransaction(CTransaction &importTx,int32_t offset); /* On assetchain */ bool CheckMoMoM(uint256 kmdNotarisationHash, uint256 momom); - +bool CheckNotariesApproval(uint256 burntxid, const std::vector & notaryTxids); #endif /* CROSSCHAIN_H */ diff --git a/src/importcoin.cpp b/src/importcoin.cpp index 6702a78dd..d1b317425 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -24,28 +24,63 @@ #include "script/sign.h" #include "wallet/wallet.h" +#include "cc/CCinclude.h" + int32_t komodo_nextheight(); -CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride) +// makes import tx for either coins or tokens +CTransaction MakeImportCoinTransaction(const ImportProof &proof, const CTransaction &burnTx, const std::vector &payouts, uint32_t nExpiryHeightOverride) { - std::vector payload = E_MARSHAL(ss << EVAL_IMPORTCOIN); + //std::vector payload = E_MARSHAL(ss << EVAL_IMPORTCOIN); + CScript scriptSig; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); if (mtx.fOverwintered) mtx.nExpiryHeight = 0; - mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload)); mtx.vout = payouts; - auto importData = E_MARSHAL(ss << proof; ss << burnTx); - mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << importData)); - if (nExpiryHeightOverride != 0) - mtx.nExpiryHeight = nExpiryHeightOverride; //this is for construction of the tx used for validating importtx + if (mtx.vout.size() == 0) + return CTransaction(mtx); + + // add special import tx vin: + scriptSig << E_MARSHAL(ss << EVAL_IMPORTCOIN); // simple payload for coins + mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), scriptSig)); + + if (nExpiryHeightOverride != 0) + mtx.nExpiryHeight = nExpiryHeightOverride; //this is for validation code, to make a tx used for validating the import tx + + auto importData = E_MARSHAL(ss << EVAL_IMPORTCOIN; ss << proof; ss << burnTx); // added evalcode to differentiate importdata from token opret + // if it is tokens: + vscript_t vopret; + GetOpReturnData(mtx.vout.back().scriptPubKey, vopret); + + if (!vopret.empty()) { + std::vector vorigpubkey; + uint8_t funcId; + std::vector > oprets; + std::string name, desc; + + if (DecodeTokenCreateOpRet(mtx.vout.back().scriptPubKey, vorigpubkey, name, desc, oprets) == 'c') { // parse token 'c' opret + mtx.vout.pop_back(); //remove old token opret + oprets.push_back(std::make_pair(OPRETID_IMPORTDATA, importData)); + mtx.vout.push_back(CTxOut(0, EncodeTokenCreateOpRet('c', vorigpubkey, name, desc, oprets))); // make new token 'c' opret with importData + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeImportCoinTransaction() incorrect token import opret" << std::endl); + } + } + else { //no opret in coin payouts + mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << importData)); // import tx's opret now is in the vout's tail + } + return CTransaction(mtx); } -CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof) +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string &targetSymbol, const std::vector &payouts, const std::vector &rawproof) { std::vector opret; - opret = E_MARSHAL(ss << VARINT(targetCCid); + opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; // should mark burn opret to differentiate it from token opret + ss << VARINT(targetCCid); ss << targetSymbol; ss << SerializeHash(payouts); ss << rawproof); @@ -87,32 +122,103 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb } -bool UnmarshalImportTx(const CTransaction importTx, TxProof &proof, CTransaction &burnTx, - std::vector &payouts) +bool UnmarshalImportTx(const CTransaction &importTx, ImportProof &proof, CTransaction &burnTx, std::vector &payouts) { - std::vector vData; - GetOpReturnData(importTx.vout[importTx.vout.size()-1].scriptPubKey, vData); - if (importTx.vout.size() < 1) return false; - payouts = std::vector(importTx.vout.begin(), importTx.vout.end()-1); - return importTx.vin.size() == 1 && - importTx.vin[0].scriptSig == (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN)) && - E_UNMARSHAL(vData, ss >> proof; ss >> burnTx); + if (importTx.vout.size() < 1) + return false; + + if (importTx.vin.size() != 1 || importTx.vin[0].scriptSig != (CScript() << E_MARSHAL(ss << EVAL_IMPORTCOIN))) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() incorrect import tx vin" << std::endl); + return false; + } + + std::vector vImportData; + GetOpReturnData(importTx.vout.back().scriptPubKey, vImportData); + if (vImportData.empty()) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() no opret" << std::endl); + return false; + } + + if (vImportData.begin()[0] == EVAL_TOKENS) { // if it is tokens + // get import data after token opret: + std::vector> oprets; + std::vector vorigpubkey; + std::string name, desc; + + if (DecodeTokenCreateOpRet(importTx.vout.back().scriptPubKey, vorigpubkey, name, desc, oprets) == 0) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() could not decode token opret" << std::endl); + return false; + } + + GetOpretBlob(oprets, OPRETID_IMPORTDATA, vImportData); // fetch import data after token opret + for (std::vector>::const_iterator i = oprets.begin(); i != oprets.end(); i++) + if ((*i).first == OPRETID_IMPORTDATA) { + oprets.erase(i); // remove import data from token opret to restore original payouts: + break; + } + + payouts = std::vector(importTx.vout.begin(), importTx.vout.end()-1); //exclude opret with import data + payouts.push_back(CTxOut(0, EncodeTokenCreateOpRet('c', vorigpubkey, name, desc, oprets))); // make original payouts token opret (without import data) + } + else { + //payouts = std::vector(importTx.vout.begin()+1, importTx.vout.end()); // see next + payouts = std::vector(importTx.vout.begin(), importTx.vout.end() - 1); // skip opret; and it is now in the back + } + + uint8_t evalCode; + bool retcode = E_UNMARSHAL(vImportData, ss >> evalCode; ss >> proof; ss >> burnTx); + if (!retcode) + LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalImportTx() could not unmarshal import data" << std::endl); + return retcode; } -bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector&rawproof) +bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector&rawproof) { - std::vector burnOpret; uint32_t ccid = 0; bool isEof=true; + std::vector vburnOpret; uint32_t ccid = 0; + uint8_t evalCode; - if (burnTx.vout.size() == 0) return false; - GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); - return E_UNMARSHAL(burnOpret, ss >> VARINT(*targetCCid); - ss >> targetSymbol; - ss >> payoutsHash; - ss >> rawproof; isEof=ss.eof();) || !isEof; + if (burnTx.vout.size() == 0) + return false; + + GetOpReturnData(burnTx.vout.back().scriptPubKey, vburnOpret); + if (vburnOpret.empty()) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() cannot unmarshal burn tx: empty burn opret" << std::endl); + return false; + } + + if (vburnOpret.begin()[0] == EVAL_TOKENS) { //if it is tokens + std::vector> oprets; + uint256 tokenid; + uint8_t evalCodeInOpret; + std::vector voutTokenPubkeys; + + if (DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) != 't') + return false; + + //skip token opret: + GetOpretBlob(oprets, OPRETID_BURNDATA, vburnOpret); // fetch burnOpret after token opret + if (vburnOpret.empty()) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() cannot unmarshal token burn tx: empty burn opret for tokenid=" << tokenid.GetHex() << std::endl); + return false; + } + } + + if (vburnOpret.begin()[0] == EVAL_IMPORTCOIN) { + uint8_t evalCode; + return E_UNMARSHAL(vburnOpret, ss >> evalCode; + ss >> VARINT(*targetCCid); + ss >> targetSymbol; + ss >> payoutsHash; + ss >> rawproof); + } + else { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() invalid eval code in opret" << std::endl); + return false; + } } -bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt) +bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &srcaddr, std::string &receipt) { std::vector burnOpret,rawproof; bool isEof=true; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; @@ -155,16 +261,55 @@ bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector payouts; - if (UnmarshalImportTx(tx, proof, burnTx, payouts)) { - return burnTx.vout.size() ? burnTx.vout.back().nValue : 0; + + bool isNewImportTx = false; + if ((isNewImportTx = UnmarshalImportTx(tx, proof, burnTx, payouts))) { + if (burnTx.vout.size() > 0) { + vscript_t vburnOpret; + + GetOpReturnData(burnTx.vout.back().scriptPubKey, vburnOpret); + if (vburnOpret.empty()) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetCoinImportValue() empty burn opret" << std::endl); + return 0; + } + + if (isNewImportTx && vburnOpret.begin()[0] == EVAL_TOKENS) { //if it is tokens + + uint8_t evalCodeInOpret; + uint256 tokenid; + std::vector voutTokenPubkeys; + std::vector> oprets; + + if (DecodeTokenOpRet(tx.vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) == 0) + return 0; + + uint8_t nonfungibleEvalCode = EVAL_TOKENS; // init as if no non-fungibles + vscript_t vnonfungibleOpret; + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vnonfungibleOpret); + if (!vnonfungibleOpret.empty()) + nonfungibleEvalCode = vnonfungibleOpret.begin()[0]; + + // calc outputs for burn tx + int64_t ccBurnOutputs = 0; + for (auto v : burnTx.vout) + if (v.scriptPubKey.IsPayToCryptoCondition() && + CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(nonfungibleEvalCode, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey + ccBurnOutputs += v.nValue; + + return ccBurnOutputs + burnTx.vout.back().nValue; // total token burned value + } + else + return burnTx.vout.back().nValue; // coin burned value + } } return 0; } + /* * CoinImport is different enough from normal script execution that it's not worth * making all the mods neccesary in the interpreter to do the dispatch correctly. diff --git a/src/importcoin.h b/src/importcoin.h index 0fcc350d0..c510fe405 100644 --- a/src/importcoin.h +++ b/src/importcoin.h @@ -22,13 +22,79 @@ #include "script/interpreter.h" #include +enum ProofKind : uint8_t { + PROOF_NONE = 0x00, + PROOF_MERKLEBRANCH = 0x11, + PROOF_NOTARYTXIDS = 0x12, + PROOF_MERKLEBLOCK = 0x13 +}; + +class ImportProof { + +private: + uint8_t proofKind; + TxProof proofBranch; + std::vector notaryTxids; + std::vector proofBlock; + +public: + ImportProof() { proofKind = PROOF_NONE; } + ImportProof(const TxProof &_proofBranch) { + proofKind = PROOF_MERKLEBRANCH; proofBranch = _proofBranch; + } + ImportProof(const std::vector &_notaryTxids) { + proofKind = PROOF_NOTARYTXIDS; notaryTxids = _notaryTxids; + } + ImportProof(const std::vector &_proofBlock) { + proofKind = PROOF_MERKLEBLOCK; proofBlock = _proofBlock; + } + + ADD_SERIALIZE_METHODS + + template + inline void SerializationOp(Stream& s, Operation ser_action) { + READWRITE(proofKind); + if (proofKind == PROOF_MERKLEBRANCH) + READWRITE(proofBranch); + else if (proofKind == PROOF_NOTARYTXIDS) + READWRITE(notaryTxids); + else if (proofKind == PROOF_MERKLEBLOCK) + READWRITE(proofBlock); + } + + bool IsMerkleBranch(TxProof &_proofBranch) const { + if (proofKind == PROOF_MERKLEBRANCH) { + _proofBranch = proofBranch; + return true; + } + else + return false; + } + bool IsNotaryTxids(std::vector &_notaryTxids) const { + if (proofKind == PROOF_NOTARYTXIDS) { + _notaryTxids = notaryTxids; + return true; + } + else + return false; + } + bool IsMerkleBlock(std::vector &_proofBlock) const { + if (proofKind == PROOF_MERKLEBLOCK) { + _proofBlock = proofBlock; + return true; + } + else + return false; + } +}; + + CAmount GetCoinImportValue(const CTransaction &tx); -CTransaction MakeImportCoinTransaction(const TxProof proof, - const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride = 0); +CTransaction MakeImportCoinTransaction(const ImportProof &proof, const CTransaction &burnTx, const std::vector &payouts, uint32_t nExpiryHeightOverride = 0); -CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof); +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string &targetSymbol, const std::vector &payouts, const std::vector &rawproof); CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof, uint256 bindtxid,std::vector publishers,std::vectortxids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount); CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof,std::string srcaddr, @@ -37,7 +103,7 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector &rawproof); bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt); bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount); -bool UnmarshalImportTx(const CTransaction importTx, TxProof &proof, CTransaction &burnTx,std::vector &payouts); +bool UnmarshalImportTx(const CTransaction &importTx, ImportProof &proof, CTransaction &burnTx,std::vector &payouts); bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state); @@ -45,4 +111,9 @@ void AddImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs, i void RemoveImportTombstone(const CTransaction &importTx, CCoinsViewCache &inputs); int ExistsImportTombstone(const CTransaction &importTx, const CCoinsViewCache &inputs); +bool CheckVinPubKey(const CTransaction &sourcetx, int32_t i, uint8_t pubkey33[33]); + +CMutableTransaction MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount); +int32_t GetSelfimportProof(const CMutableTransaction &sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull); + #endif /* IMPORTCOIN_H */ diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index cacf4357e..7f50c32ee 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -38,6 +38,7 @@ #include "key_io.h" #include "cc/CCImportGateway.h" +#include "cc/CCtokens.h" #include #include @@ -52,6 +53,8 @@ extern std::string CCerror; extern std::string ASSETCHAINS_SELFIMPORT; extern uint16_t ASSETCHAINS_CODAPORT, ASSETCHAINS_BEAMPORT; int32_t ensure_CCrequirements(uint8_t evalcode); +bool EnsureWalletIsAvailable(bool avoidException); + int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip); int32_t komodo_MoMoMdata(char *hexstr,int32_t hexsize,struct komodo_ccdataMoMoM *mdata,char *symbol,int32_t kmdheight,int32_t notarized_height); @@ -60,8 +63,8 @@ uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth); int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); extern std::string ASSETCHAINS_SELFIMPORT; -std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx); -int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount); +//std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx); +//int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount); std::string MakeCodaImportTx(uint64_t txfee, std::string receipt, std::string srcaddr, std::vector vouts); UniValue assetchainproof(const UniValue& params, bool fHelp) @@ -185,7 +188,7 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp) "If neccesary, the transaction should be funded using fundrawtransaction.\n" "Finally, the transaction should be signed using signrawtransaction\n" "The finished export transaction, plus the payouts, should be passed to " - "the \"migrate_createimporttransaction\" method on a KMD node to get the corresponding " + "the \"migrate_createimporttransaction\" method to get the corresponding " "import transaction.\n" ); @@ -206,19 +209,30 @@ UniValue migrate_converttoexport(const UniValue& params, bool fHelp) if (strcmp(ASSETCHAINS_SYMBOL,targetSymbol.c_str()) == 0) throw runtime_error("cant send a coin to the same chain"); + + /// Tested 44 vins p2pkh inputs as working. Set this at 25, but its a tx size limit. + // likely with a single RPC you can limit it by the size of tx. + if (tx.vout.size() > 25) + throw JSONRPCError(RPC_TYPE_ERROR, "Cannot have more than 50 vins, transaction too large."); CAmount burnAmount = 0; for (int i=0; i 1000000LL*COIN) throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export more than 1 million coins per export."); + /* note: we marshal to rawproof in a different way (to be able to add other objects) rawproof.resize(strlen(ASSETCHAINS_SYMBOL)); ptr = rawproof.data(); for (i=0; i 32) + throw runtime_error("targetSymbol length must be >0 and <=32"); + + if (strcmp(ASSETCHAINS_SYMBOL, targetSymbol.c_str()) == 0) + throw runtime_error("cant send a coin to the same chain"); + + std::string dest_addr_or_pubkey = params[1].get_str(); + + CAmount burnAmount; + if(params.size() == 3) + burnAmount = (CAmount)( atof(params[2].get_str().c_str()) * COIN + 0.00000000499999 ); + else + burnAmount = atoll(params[2].get_str().c_str()); + + if (burnAmount <= 0) + throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export a negative or zero value."); + if (burnAmount > 1000000LL * COIN) + throw JSONRPCError(RPC_TYPE_ERROR, "Cannot export more than 1 million coins per export."); + + uint256 tokenid = zeroid; + if( params.size() == 4 ) + tokenid = Parseuint256(params[3].get_str().c_str()); + + CPubKey myPubKey = Mypubkey(); + struct CCcontract_info *cpTokens, C; + cpTokens = CCinit(&C, EVAL_TOKENS); + + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + + const std::string chainSymbol(ASSETCHAINS_SYMBOL); + std::vector rawproof; //(chainSymbol.begin(), chainSymbol.end()); + + if (tokenid.IsNull()) { // coins + int64_t inputs; + if ((inputs = AddNormalinputs(mtx, myPubKey, burnAmount + txfee, 60)) == 0) { + throw runtime_error("Cannot find normal inputs\n"); + } + + CTxDestination txdest = DecodeDestination(dest_addr_or_pubkey.c_str()); + CScript scriptPubKey = GetScriptForDestination(txdest); + if (!scriptPubKey.IsPayToPublicKeyHash()) { + throw JSONRPCError(RPC_TYPE_ERROR, "Incorrect destination addr."); + } + mtx.vout.push_back(CTxOut(burnAmount, scriptPubKey)); // 'model' vout + ret.push_back(Pair("payouts", HexStr(E_MARSHAL(ss << mtx.vout)))); // save 'model' vout + + rawproof = E_MARSHAL(ss << chainSymbol); // add src chain name + + CTxOut burnOut = MakeBurnOutput(burnAmount+txfee, ccid, targetSymbol, mtx.vout, rawproof); //make opret with burned amount + + mtx.vout.clear(); // remove 'model' vout + + int64_t change = inputs - (burnAmount+txfee); + if (change != 0) + mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG)); // make change here to prevent it from making in FinalizeCCtx + + mtx.vout.push_back(burnOut); // mtx now has only burned vout (that is, amount sent to OP_RETURN making it unspendable) + //std::string exportTxHex = FinalizeCCTx(0, cpTokens, mtx, myPubKey, txfee, CScript()); // no change no opret + + } + else { // tokens + CTransaction tokenbasetx; + uint256 hashBlock; + vscript_t vopretNonfungible; + vscript_t vopretBurnData; + std::vector vorigpubkey, vdestpubkey; + std::string name, description; + std::vector> oprets; + + if (!myGetTransaction(tokenid, tokenbasetx, hashBlock)) + throw runtime_error("Could not load token creation tx\n"); + + // check if it is non-fungible tx and get its second evalcode from non-fungible payload + if (tokenbasetx.vout.size() == 0) + throw runtime_error("No vouts in token tx\n"); + + if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, description, oprets) != 'c') + throw runtime_error("Incorrect token creation tx\n"); + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); + /* allow fungible tokens: + if (vopretNonfungible.empty()) + throw runtime_error("No non-fungible token data\n"); */ + + uint8_t destEvalCode = EVAL_TOKENS; + if (!vopretNonfungible.empty()) + destEvalCode = vopretNonfungible.begin()[0]; + + // check non-fungible tokens amount + if (!vopretNonfungible.empty() && burnAmount != 1) + throw JSONRPCError(RPC_TYPE_ERROR, "For non-fungible tokens amount should be equal to 1."); + + vdestpubkey = ParseHex(dest_addr_or_pubkey); + CPubKey destPubKey = pubkey2pk(vdestpubkey); + if (!destPubKey.IsValid()) + throw runtime_error("Invalid destination pubkey\n"); + + int64_t inputs; + if ((inputs = AddNormalinputs(mtx, myPubKey, txfee, 1)) == 0) // for miners in dest chain + throw runtime_error("No normal input found for two txfee\n"); + + int64_t ccInputs; + if ((ccInputs = AddTokenCCInputs(cpTokens, mtx, myPubKey, tokenid, burnAmount, 4)) < burnAmount) + throw runtime_error("No token inputs found (please try to consolidate tokens)\n"); + + // make payouts (which will be in the import tx with token): + mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens, NULL))); // new marker to token cc addr, burnable and validated, vout position now changed to 0 (from 1) + mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, burnAmount, destPubKey)); + + std::vector> voprets; + if (!vopretNonfungible.empty()) + voprets.push_back(std::make_pair(OPRETID_NONFUNGIBLEDATA, vopretNonfungible)); // add additional opret with non-fungible data + + mtx.vout.push_back(CTxOut((CAmount)0, EncodeTokenCreateOpRet('c', vorigpubkey, name, description, voprets))); // make token import opret + ret.push_back(Pair("payouts", HexStr(E_MARSHAL(ss << mtx.vout)))); // save payouts for import tx + + rawproof = E_MARSHAL(ss << chainSymbol << tokenbasetx); // add src chain name and token creation tx + + CTxOut burnOut = MakeBurnOutput(0, ccid, targetSymbol, mtx.vout, rawproof); //make opret with amount=0 because tokens are burned, not coins (see next vout) + mtx.vout.clear(); // remove payouts + + // now make burn transaction: + mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, burnAmount, pubkey2pk(ParseHex(CC_BURNPUBKEY)))); // burn tokens + + int64_t change = inputs - txfee; + if (change != 0) + mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG)); // make change here to prevent it from making in FinalizeCCtx + + std::vector voutTokenPubkeys; + voutTokenPubkeys.push_back(pubkey2pk(ParseHex(CC_BURNPUBKEY))); // maybe we do not need this because ccTokens has the const for burn pubkey + + int64_t ccChange = ccInputs - burnAmount; + if (ccChange != 0) + mtx.vout.push_back(MakeTokensCC1vout(destEvalCode, ccChange, myPubKey)); + + GetOpReturnData(burnOut.scriptPubKey, vopretBurnData); + mtx.vout.push_back(CTxOut(txfee, EncodeTokenOpRet(tokenid, voutTokenPubkeys, std::make_pair(OPRETID_BURNDATA, vopretBurnData)))); //burn txfee for miners in dest chain + } + + std::string burnTxHex = FinalizeCCTx(0, cpTokens, mtx, myPubKey, txfee, CScript()); //no change, no opret + ret.push_back(Pair("BurnTxHex", burnTxHex)); + return ret; +} + +// util func to check burn tx and source chain params +void CheckBurnTxSource(uint256 burntxid, UniValue &info) { + + CTransaction burnTx; + uint256 blockHash; + + if (!GetTransaction(burntxid, burnTx, blockHash, true)) + throw std::runtime_error("Cannot find burn transaction"); + + if (blockHash.IsNull()) + throw std::runtime_error("Burn tx still in mempool"); + + uint256 payoutsHash; + std::string targetSymbol; + uint32_t targetCCid; + std::vector rawproof; + + if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCCid, payoutsHash, rawproof)) + throw std::runtime_error("Cannot unmarshal burn tx data"); + + vscript_t vopret; + std::string sourceSymbol; + CTransaction tokenbasetxStored; + uint256 tokenid = zeroid; + + if (burnTx.vout.size() > 0 && GetOpReturnData(burnTx.vout.back().scriptPubKey, vopret) && !vopret.empty()) { + if (vopret.begin()[0] == EVAL_TOKENS) { + if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol; ss >> tokenbasetxStored)) + throw std::runtime_error("Cannot unmarshal rawproof for tokens"); + + uint8_t evalCode; + std::vector voutPubkeys; + std::vector> oprets; + if( DecodeTokenOpRet(burnTx.vout.back().scriptPubKey, evalCode, tokenid, voutPubkeys, oprets) == 0 ) + throw std::runtime_error("Cannot decode token opret in burn tx"); + + if( tokenid != tokenbasetxStored.GetHash() ) + throw std::runtime_error("Incorrect tokenbase in burn tx"); + + CTransaction tokenbasetx; + uint256 hashBlock; + if (!myGetTransaction(tokenid, tokenbasetx, hashBlock)) { + throw std::runtime_error("Could not load tokenbase tx"); + } + + // check if nonfungible data present + if (tokenbasetx.vout.size() > 0) { + std::vector origpubkey; + std::string name, description; + std::vector> oprets; + + vscript_t vopretNonfungible; + if (DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, origpubkey, name, description, oprets) == 'c') { + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); + if (vopretNonfungible.empty()) + throw std::runtime_error("Could not migrate fungible tokens"); + } + else + throw std::runtime_error("Could not decode opreturn in tokenbase tx"); + } + else + throw std::runtime_error("Incorrect tokenbase tx: not opreturn"); + + + struct CCcontract_info *cpTokens, CCtokens_info; + cpTokens = CCinit(&CCtokens_info, EVAL_TOKENS); + int64_t ccInputs = 0, ccOutputs = 0; + if( !TokensExactAmounts(true, cpTokens, ccInputs, ccOutputs, NULL, burnTx, tokenid) ) + throw std::runtime_error("Incorrect token burn tx: cc inputs <> cc outputs"); + } + else if (vopret.begin()[0] == EVAL_IMPORTCOIN) { + if (!E_UNMARSHAL(rawproof, ss >> sourceSymbol)) + throw std::runtime_error("Cannot unmarshal rawproof for coins"); + } + else + throw std::runtime_error("Incorrect eval code in opreturn"); + } + else + throw std::runtime_error("No opreturn in burn tx"); + + + if (sourceSymbol != ASSETCHAINS_SYMBOL) + throw std::runtime_error("Incorrect source chain in rawproof"); + + if (targetCCid != ASSETCHAINS_CC) + throw std::runtime_error("Incorrect CCid in burn tx"); + + if (targetSymbol == ASSETCHAINS_SYMBOL) + throw std::runtime_error("Must not be called on the destination chain"); + + // fill info to return for the notary operator (if manual notarization) or user + info.push_back(Pair("SourceSymbol", sourceSymbol)); + info.push_back(Pair("TargetSymbol", targetSymbol)); + info.push_back(Pair("TargetCCid", std::to_string(targetCCid))); + if (!tokenid.IsNull()) + info.push_back(Pair("tokenid", tokenid.GetHex())); + +} /* - * The process to migrate funds + * The process to migrate funds from a chain to chain * - * Create a transaction on assetchain: + * 1.Create a transaction on assetchain (deprecated): + * 1.1 generaterawtransaction + * 1.2 migrate_converttoexport + * 1.3 fundrawtransaction + * 1.4 signrawtransaction * - * generaterawtransaction - * migrate_converttoexport - * fundrawtransaction - * signrawtransaction + * alternatively, burn (export) transaction may be created with this new rpc call: + * 1. migrate_createburntransaction * - * migrate_createimportransaction - * migrate_completeimporttransaction + * next steps: + * 2. migrate_createimporttransaction + * 3. migrate_completeimporttransaction */ UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp) { - if (fHelp || params.size() != 2) - throw runtime_error("migrate_createimporttransaction burnTx payouts\n\n" - "Create an importTx given a burnTx and the corresponding payouts, hex encoded"); + if (fHelp || params.size() < 2) + throw runtime_error("migrate_createimporttransaction burnTx payouts [notarytxid-1]..[notarytxid-N]\n\n" + "Create an importTx given a burnTx and the corresponding payouts, hex encoded\n" + "optional notarytxids are txids of notary operator proofs of burn tx existense (from destination chain).\n" + "Do not make subsequent call to migrate_completeimporttransaction if notary txids are set"); if (ASSETCHAINS_CC < KOMODO_FIRSTFUNGIBLEID) throw runtime_error("-ac_cc < KOMODO_FIRSTFUNGIBLEID"); @@ -261,27 +557,52 @@ UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp) if (!E_UNMARSHAL(txData, ss >> burnTx)) throw runtime_error("Couldn't parse burnTx"); + if( burnTx.vin.size() == 0 ) + throw runtime_error("No vins in the burnTx"); + + if (burnTx.vout.size() == 0) + throw runtime_error("No vouts in the burnTx"); + vector payouts; if (!E_UNMARSHAL(ParseHexV(params[1], "argument 2"), ss >> payouts)) throw runtime_error("Couldn't parse payouts"); - uint256 txid = burnTx.GetHash(); - TxProof proof = GetAssetchainProof(burnTx.GetHash(),burnTx); + ImportProof importProof; + if (params.size() == 2) { // standard MoMoM based notarization + // get MoM import proof + importProof = ImportProof(GetAssetchainProof(burnTx.GetHash(), burnTx)); + } + else { // notarization by manual operators notary tx + UniValue info(UniValue::VOBJ); + CheckBurnTxSource(burnTx.GetHash(), info); - CTransaction importTx = MakeImportCoinTransaction(proof, burnTx, payouts); + // get notary import proof + std::vector notaryTxids; + for (int i = 2; i < params.size(); i++) { + uint256 txid = Parseuint256(params[i].get_str().c_str()); + if (txid.IsNull()) + throw runtime_error("Incorrect notary approval txid"); + notaryTxids.push_back(txid); + } + importProof = ImportProof(notaryTxids); + } - return HexStr(E_MARSHAL(ss << importTx)); + CTransaction importTx = MakeImportCoinTransaction(importProof, burnTx, payouts); + + std::string importTxHex = HexStr(E_MARSHAL(ss << importTx)); + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("ImportTxHex", importTxHex)); + return ret; } - UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error("migrate_completeimporttransaction importTx (offset)\n\n" + throw runtime_error("migrate_completeimporttransaction importTx [offset]\n\n" "Takes a cross chain import tx with proof generated on assetchain " "and extends proof to target chain proof root\n" - "offset is optional, use it to increase the used KMD height, use when import fails on target."); + "offset is optional, use it to increase the used KMD height, use when import fails."); if (ASSETCHAINS_SYMBOL[0] != 0) throw runtime_error("Must be called on KMD"); @@ -289,67 +610,130 @@ UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp) CTransaction importTx; if (!E_UNMARSHAL(ParseHexV(params[0], "argument 1"), ss >> importTx)) throw runtime_error("Couldn't parse importTx"); - + int32_t offset = 0; if ( params.size() == 2 ) offset = params[1].get_int(); - + CompleteImportTransaction(importTx, offset); - return HexStr(E_MARSHAL(ss << importTx)); + std::string importTxHex = HexStr(E_MARSHAL(ss << importTx)); + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("ImportTxHex", importTxHex)); + return ret; } +/* +* Alternate coin migration solution if MoMoM migration has failed +* +* The workflow: +* On the source chain user calls migrate_createburntransaction, sends the burn tx to the chain and sends its txid and the source chain name to the notary operators (off-chain) +* the notary operators call migrate_checkburntransactionsource on the source chain +* on the destination chain the notary operators call migrate_createnotaryapprovaltransaction and pass the burn txid and txoutproof received from the previous call, +* the notary operators send the approval transactions to the chain and send their txids to the user (off-chain) +* on the source chain the user calls migrate_createimporttransaction and passes to it notary txids as additional parameters +* then the user sends the import transaction to the destination chain (where the notary approvals will be validated) +*/ + +// checks if burn tx exists and params stored in the burn tx match to the source chain +// returns txproof +// run it on the source chain +UniValue migrate_checkburntransactionsource(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error("migrate_checkburntransactionsource burntxid\n\n" + "checks if params stored in the burn tx match to its tx chain"); + + if (ASSETCHAINS_SYMBOL[0] == 0) + throw runtime_error("Must be called on asset chain"); + + uint256 burntxid = Parseuint256(params[0].get_str().c_str()); + UniValue result(UniValue::VOBJ); + CheckBurnTxSource(burntxid, result); // check and get burn tx data + + // get tx proof for burn tx + UniValue nextparams(UniValue::VARR); + UniValue txids(UniValue::VARR); + txids.push_back(burntxid.GetHex()); + nextparams.push_back(txids); + result.push_back(Pair("TxOutProof", gettxoutproof(nextparams, false))); // get txoutproof + result.push_back(Pair("result", "success")); // get txoutproof + + return result; +} + +// creates a tx for the dest chain with txproof +// used as a momom-backup manual import solution +// run it on the dest chain +UniValue migrate_createnotaryapprovaltransaction(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error("migrate_createnotaryapprovaltransaction burntxid txoutproof\n\n" + "Creates a tx for destination chain with burn tx proof\n" + "txoutproof should be retrieved by komodo-cli migrate_checkburntransactionsource call on the source chain\n" ); + + if (ASSETCHAINS_SYMBOL[0] == 0) + throw runtime_error("Must be called on asset chain"); + + uint256 burntxid = Parseuint256(params[0].get_str().c_str()); + if (burntxid.IsNull()) + throw runtime_error("Couldn't parse burntxid or it is null"); + + std::vector proofData = ParseHex(params[1].get_str()); + CMerkleBlock merkleBlock; + std::vector prooftxids; + if (!E_UNMARSHAL(proofData, ss >> merkleBlock)) + throw runtime_error("Couldn't parse txoutproof"); + + merkleBlock.txn.ExtractMatches(prooftxids); + if (std::find(prooftxids.begin(), prooftxids.end(), burntxid) == prooftxids.end()) + throw runtime_error("No burntxid in txoutproof"); + + const int64_t txfee = 10000; + struct CCcontract_info *cpDummy, C; + cpDummy = CCinit(&C, EVAL_TOKENS); // just for FinalizeCCtx to work + + // creating a tx with proof: + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + if (AddNormalinputs(mtx, Mypubkey(), txfee*2, 4) == 0) + throw runtime_error("Cannot find normal inputs\n"); + + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(Mypubkey())) << OP_CHECKSIG)); + std::string notaryTxHex = FinalizeCCTx(0, cpDummy, mtx, Mypubkey(), txfee, CScript() << OP_RETURN << E_MARSHAL(ss << proofData;)); + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("NotaryTxHex", notaryTxHex)); + return result; +} + +// creates a source 'quasi-burn' tx for AC_PUBKEY +// run it on the same asset chain UniValue selfimport(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); - CMutableTransaction sourceMtx, templateMtx; std::string destaddr; std::string source; - std::string rawsourcetx; + std::string sourceTxHex; + std::string importTxHex; CTransaction burnTx; CTxOut burnOut; uint64_t burnAmount; uint256 sourcetxid, blockHash; std::vector vouts; - std::vector rawproof, rawproofEmpty; - int32_t ivout = 0; - CScript scriptPubKey; - TxProof proof; + std::vector rawproof; if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) throw runtime_error("selfimport only works on -ac_import chains"); if (fHelp || params.size() != 2) throw runtime_error("selfimport destaddr amount\n" - //old: "selfimport rawsourcetx sourcetxid {nvout|\"find\"} amount \n" //TODO: "or selfimport rawburntx burntxid {nvout|\"find\"} rawproof source bindtxid height} \n" "\ncreates self import coin transaction"); -/* OLD selfimport schema: - rawsourcetx = params[0].get_str(); - sourcetxid = Parseuint256((char *)params[1].get_str().c_str()); // allow for txid != hash(rawtx) - - int32_t ivout = -1; - if( params[2].get_str() != "find" ) { - if( !std::all_of(params[2].get_str().begin(), params[2].get_str().end(), ::isdigit) ) // check if not all chars are digit - throw std::runtime_error("incorrect nvout param"); - - ivout = atoi(params[2].get_str().c_str()); - } - - burnAmount = atof(params[3].get_str().c_str()) * COIN + 0.00000000499999; */ - destaddr = params[0].get_str(); burnAmount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999; source = ASSETCHAINS_SELFIMPORT; //defaults to -ac_import=... param - /* TODO for gateways: - if ( params.size() >= 5 ) - { - rawproof = ParseHex(params[4].get_str().c_str()); - if ( params.size() == 6 ) - source = params[5].get_str(); - } */ if (source == "BEAM") { @@ -369,51 +753,34 @@ UniValue selfimport(const UniValue& params, bool fHelp) } else if (source == "PUBKEY") { - + ImportProof proofNull; CTxDestination dest = DecodeDestination(destaddr.c_str()); - rawsourcetx = MakeSelfImportSourceTx(dest, burnAmount, sourceMtx); - sourcetxid = sourceMtx.GetHash(); - + CMutableTransaction sourceMtx = MakeSelfImportSourceTx(dest, burnAmount); // make self-import source tx + vscript_t rawProofEmpty; + + CMutableTransaction templateMtx; // prepare self-import 'quasi-burn' tx and also create vout for import tx (in mtx.vout): - if (GetSelfimportProof(source, templateMtx, scriptPubKey, proof, rawsourcetx, ivout, sourcetxid, burnAmount) < 0) - throw std::runtime_error("Failed validating selfimport"); + if (GetSelfimportProof(sourceMtx, templateMtx, proofNull) < 0) + throw std::runtime_error("Failed creating selfimport template tx"); vouts = templateMtx.vout; - burnOut = MakeBurnOutput(burnAmount, 0xffffffff, ASSETCHAINS_SELFIMPORT, vouts, rawproofEmpty); + burnOut = MakeBurnOutput(burnAmount, 0xffffffff, ASSETCHAINS_SELFIMPORT, vouts, rawProofEmpty); templateMtx.vout.clear(); templateMtx.vout.push_back(burnOut); // burn tx has only opret with vouts and optional proof burnTx = templateMtx; // complete the creation of 'quasi-burn' tx - std::string hextx = HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proof, burnTx, vouts))); - - CTxDestination address; - bool fValidAddress = ExtractDestination(scriptPubKey, address); - - result.push_back(Pair("sourceTxHex", rawsourcetx)); - result.push_back(Pair("importTxHex", hextx)); - result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx - result.push_back(Pair("DestinationAddress", EncodeDestination(address))); // notify user about the address where the funds will be sent - + sourceTxHex = HexStr(E_MARSHAL(ss << sourceMtx)); + importTxHex = HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proofNull, burnTx, vouts))); + + result.push_back(Pair("SourceTxHex", sourceTxHex)); + result.push_back(Pair("ImportTxHex", importTxHex)); + return result; } else if (source == ASSETCHAINS_SELFIMPORT) { - throw std::runtime_error("not implemented yet\n"); - - if (params.size() != 8) - throw runtime_error("use \'selfimport rawburntx burntxid nvout rawproof source bindtxid height\' to import from a coin chain\n"); - - uint256 bindtxid = Parseuint256((char *)params[6].get_str().c_str()); - int32_t height = atoi((char *)params[7].get_str().c_str()); - - - // source is external coin is the assetchains symbol in the burnTx OP_RETURN - // burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent - //std::string hextx = MakeGatewaysImportTx(0, bindtxid, height, source, rawproof, rawsourcetx, ivout, ""); - - // result.push_back(Pair("hex", hextx)); - // result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx + return -1; } return result; } @@ -939,14 +1306,15 @@ UniValue getimports(const UniValue& params, bool fHelp) { UniValue objTx(UniValue::VOBJ); objTx.push_back(Pair("txid",tx.GetHash().ToString())); - TxProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; - TotalImported += tx.vout[0].nValue; - objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[0].nValue))); - if (ExtractDestination(tx.vout[0].scriptPubKey, importaddress)) + ImportProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; + TotalImported += tx.vout[1].nValue; + objTx.push_back(Pair("amount", ValueFromAmount(tx.vout[1].nValue))); + if (ExtractDestination(tx.vout[1].scriptPubKey, importaddress)) { objTx.push_back(Pair("address", CBitcoinAddress(importaddress).ToString())); } - UniValue objBurnTx(UniValue::VOBJ); + UniValue objBurnTx(UniValue::VOBJ); + CPubKey vinPubkey; if (UnmarshalImportTx(tx, proof, burnTx, payouts)) { if (burnTx.vout.size() == 0) @@ -959,8 +1327,14 @@ UniValue getimports(const UniValue& params, bool fHelp) { if (rawproof.size() > 0) { - std::string sourceSymbol(rawproof.begin(), rawproof.end()); + std::string sourceSymbol; + CTransaction tokenbasetx; + E_UNMARSHAL(rawproof, ss >> sourceSymbol; + if (!ss.eof()) + ss >> tokenbasetx ); objBurnTx.push_back(Pair("source", sourceSymbol)); + if( !tokenbasetx.IsNull() ) + objBurnTx.push_back(Pair("tokenid", tokenbasetx.GetHash().GetHex())); } } } @@ -973,3 +1347,137 @@ UniValue getimports(const UniValue& params, bool fHelp) result.push_back(Pair("time", block.GetBlockTime())); return result; } + + +// outputs burn transactions in the wallet +UniValue getwalletburntransactions(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() > 1) + throw runtime_error( + "getwalletburntransactions \"count\"\n\n" + "Lists most recent wallet burn transactions up to \'count\' parameter\n" + "parameter \'count\' is optional. If omitted, defaults to 10 burn transactions" + "\n\n" + "\nResult:\n" + "[\n" + " {\n" + " \"txid\": (string)\n" + " \"burnedAmount\" : (numeric)\n" + " \"targetSymbol\" : (string)\n" + " \"targetCCid\" : (numeric)\n" + " }\n" + "]\n" + "\nExamples:\n" + + HelpExampleCli("getwalletburntransactions", "100") + + HelpExampleRpc("getwalletburntransactions", "100") + + HelpExampleCli("getwalletburntransactions", "") + + HelpExampleRpc("getwalletburntransactions", "") + ); + + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + LOCK2(cs_main, pwalletMain->cs_wallet); + + string strAccount = "*"; + isminefilter filter = ISMINE_SPENDABLE; + int nCount = 10; + + if (params.size() == 1) + nCount = atoi(params[0].get_str()); + if (nCount < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); + + UniValue ret(UniValue::VARR); + + std::list acentries; + CWallet::TxItems txOrdered = pwalletMain->OrderedTxItems(acentries, strAccount); + + // iterate backwards until we have nCount items to return: + for (CWallet::TxItems::reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it) + { + CWalletTx *const pwtx = (*it).second.first; + if (pwtx != 0) + { + LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "pwtx iterpos=" << (int32_t)pwtx->nOrderPos << " txid=" << pwtx->GetHash().GetHex() << std::endl); + vscript_t vopret; + std::string targetSymbol; + uint32_t targetCCid; uint256 payoutsHash; + std::vector rawproof; + + if (pwtx->vout.size() > 0 && GetOpReturnData(pwtx->vout.back().scriptPubKey, vopret) && !vopret.empty() && + UnmarshalBurnTx(*pwtx, targetSymbol, &targetCCid, payoutsHash, rawproof)) { + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("txid", pwtx->GetHash().GetHex())); + if (vopret.begin()[0] == EVAL_TOKENS) { + // get burned token value + std::vector> oprets; + uint256 tokenid; + uint8_t evalCodeInOpret; + std::vector voutTokenPubkeys; + + //skip token opret: + if (DecodeTokenOpRet(pwtx->vout.back().scriptPubKey, evalCodeInOpret, tokenid, voutTokenPubkeys, oprets) != 0) { + CTransaction tokenbasetx; + uint256 hashBlock; + + if (myGetTransaction(tokenid, tokenbasetx, hashBlock)) { + std::vector vorigpubkey; + std::string name, description; + std::vector> oprets; + + if (tokenbasetx.vout.size() > 0 && + DecodeTokenCreateOpRet(tokenbasetx.vout.back().scriptPubKey, vorigpubkey, name, description, oprets) == 'c') + { + uint8_t destEvalCode = EVAL_TOKENS; // init set to fungible token: + vscript_t vopretNonfungible; + GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); + if (!vopretNonfungible.empty()) + destEvalCode = vopretNonfungible.begin()[0]; + + int64_t burnAmount = 0; + for (auto v : pwtx->vout) + if (v.scriptPubKey.IsPayToCryptoCondition() && + CTxOut(v.nValue, v.scriptPubKey) == MakeTokensCC1vout(destEvalCode ? destEvalCode : EVAL_TOKENS, v.nValue, pubkey2pk(ParseHex(CC_BURNPUBKEY)))) // burned to dead pubkey + burnAmount += v.nValue; + + entry.push_back(Pair("burnedAmount", ValueFromAmount(burnAmount))); + entry.push_back(Pair("tokenid", tokenid.GetHex())); + } + } + } + } + else + entry.push_back(Pair("burnedAmount", ValueFromAmount(pwtx->vout.back().nValue))); // coins + entry.push_back(Pair("targetSymbol", targetSymbol)); + entry.push_back(Pair("targetCCid", std::to_string(targetCCid))); + if (mytxid_inmempool(pwtx->GetHash())) + entry.push_back(Pair("inMempool", "yes")); + ret.push_back(entry); + } + } //else fprintf(stderr,"null pwtx\n + if ((int)ret.size() >= (nCount)) + break; + } + // ret is newest to oldest + + if (nCount > (int)ret.size()) + nCount = ret.size(); + + vector arrTmp = ret.getValues(); + + vector::iterator first = arrTmp.begin(); + vector::iterator last = arrTmp.begin(); + std::advance(last, nCount); + + if (last != arrTmp.end()) arrTmp.erase(last, arrTmp.end()); + if (first != arrTmp.begin()) arrTmp.erase(arrTmp.begin(), first); + + std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest + + ret.clear(); + ret.setArray(); + ret.push_backV(arrTmp); + + return ret; +} \ No newline at end of file diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index fc34a2a3f..1b6442865 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -350,9 +350,12 @@ static const CRPCCommand vRPCCommands[] = { "crosschain", "getNotarisationsForBlock", &getNotarisationsForBlock, true }, { "crosschain", "scanNotarisationsDB", &scanNotarisationsDB, true }, { "crosschain", "getimports", &getimports, true }, + { "crosschain", "getwalletburntransactions", &getwalletburntransactions, true }, { "crosschain", "migrate_converttoexport", &migrate_converttoexport, true }, { "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true }, { "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true }, + { "crosschain", "migrate_checkburntransactionsource", &migrate_checkburntransactionsource, true }, + { "crosschain", "migrate_createnotaryapprovaltransaction", &migrate_createnotaryapprovaltransaction, true }, { "crosschain", "selfimport", &selfimport, true }, { "crosschain", "importdual", &importdual, true }, //ImportGateway diff --git a/src/rpc/server.h b/src/rpc/server.h index d8fd0e736..db8906f1f 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -478,9 +478,12 @@ extern UniValue crosschainproof(const UniValue& params, bool fHelp); extern UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp); extern UniValue scanNotarisationsDB(const UniValue& params, bool fHelp); extern UniValue getimports(const UniValue& params, bool fHelp); +extern UniValue getwalletburntransactions(const UniValue& params, bool fHelp); extern UniValue migrate_converttoexport(const UniValue& params, bool fHelp); extern UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp); extern UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp); +extern UniValue migrate_checkburntransactionsource(const UniValue& params, bool fHelp); +extern UniValue migrate_createnotaryapprovaltransaction(const UniValue& params, bool fHelp); extern UniValue notaries(const UniValue& params, bool fHelp); extern UniValue minerids(const UniValue& params, bool fHelp); From d87f6a158a6f1e4ac6e7c5ef1699efae5f0cb459 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 18 Apr 2019 17:06:20 +0500 Subject: [PATCH 12/43] rawtransaction corr importproof type --- src/rpc/rawtransaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 6e90c4db5..c5d2bea86 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -203,7 +203,7 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& in.push_back(Pair("coinbase", HexStr(txin.scriptSig.begin(), txin.scriptSig.end()))); else if (tx.IsCoinImport()) { in.push_back(Pair("is_import", "1")); - TxProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; + ImportProof proof; CTransaction burnTx; std::vector payouts; CTxDestination importaddress; if (UnmarshalImportTx(tx, proof, burnTx, payouts)) { if (burnTx.vout.size() == 0) From a11333e76646dfc76860b1825ba88dbbba3d5b87 Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 18 Apr 2019 17:28:43 +0500 Subject: [PATCH 13/43] importproof proc read bad id --- src/importcoin.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/importcoin.h b/src/importcoin.h index c510fe405..febf93d61 100644 --- a/src/importcoin.h +++ b/src/importcoin.h @@ -60,6 +60,8 @@ public: READWRITE(notaryTxids); else if (proofKind == PROOF_MERKLEBLOCK) READWRITE(proofBlock); + else + proofKind = PROOF_NONE; // if we have read some trash } bool IsMerkleBranch(TxProof &_proofBranch) const { From f9eaf192b43baee2d13ce9552ad63235de072b0b Mon Sep 17 00:00:00 2001 From: dimxy Date: Thu, 18 Apr 2019 20:55:59 +0500 Subject: [PATCH 14/43] burn tx isEof check added --- src/importcoin.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/importcoin.cpp b/src/importcoin.cpp index d1b317425..d378aeec6 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -206,11 +206,13 @@ bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint if (vburnOpret.begin()[0] == EVAL_IMPORTCOIN) { uint8_t evalCode; + bool isEof = true; return E_UNMARSHAL(vburnOpret, ss >> evalCode; ss >> VARINT(*targetCCid); ss >> targetSymbol; ss >> payoutsHash; - ss >> rawproof); + ss >> rawproof; isEof = ss.eof();) || !isEof; // if isEof == false it means we successfully read add the data + // and it might be additional data further that we do not need here } else { LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() invalid eval code in opret" << std::endl); From 53a7f69501fa592f7fe186e2e3fc7f0f84f65b33 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 19 Apr 2019 15:17:47 +0500 Subject: [PATCH 15/43] rebased onto latest FSM with gateways import --- src/cc/import.cpp | 10 +++++----- src/importcoin.cpp | 28 +++++++++++++++++----------- src/importcoin.h | 8 ++++---- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/cc/import.cpp b/src/cc/import.cpp index 45dd16732..913bf0295 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -519,7 +519,7 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti return(0); } -bool CheckFungible(Eval *eval, const CTransaction &importTx, const CTransaction &burnTx, std::vector & payouts, const ImportProof &proof, const std::vector &rawproof) +bool CheckMigration(Eval *eval, const CTransaction &importTx, const CTransaction &burnTx, std::vector & payouts, const ImportProof &proof, const std::vector &rawproof) { if (strcmp(ASSETCHAINS_SYMBOL, "CFEKDIMXY6") == 0 && chainActive.Height() <= 10699) return true; @@ -649,12 +649,12 @@ bool Eval::ImportCoin(const std::vector params, const CTransaction &imp ImportProof proof; CTransaction burnTx; std::vector payouts; - CAmount txfee = 10000; + CAmount txfee = 10000, amount; int32_t height, burnvout; std::vector publishers; uint32_t targetCcid; std::string targetSymbol, srcaddr, destaddr, receipt, rawburntx; - uint256 payoutsHash, bindtxid; + uint256 payoutsHash, bindtxid, burntxid; std::vector rawproof; std::vector txids; CPubKey destpub; @@ -700,8 +700,8 @@ bool Eval::ImportCoin(const std::vector params, const CTransaction &imp if (targetCcid != GetAssetchainsCC() || targetSymbol != GetAssetchainsSymbol()) return Invalid("importcoin-wrong-chain"); - if (!CheckFungible(this, importTx, burnTx, payouts, proof, rawproof)) - return false; + if (!CheckMigration(this, importTx, burnTx, payouts, proof, rawproof)) + return false; // eval->Invalid() is called in the func } else { diff --git a/src/importcoin.cpp b/src/importcoin.cpp index d378aeec6..921d9a745 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -29,7 +29,7 @@ int32_t komodo_nextheight(); // makes import tx for either coins or tokens -CTransaction MakeImportCoinTransaction(const ImportProof &proof, const CTransaction &burnTx, const std::vector &payouts, uint32_t nExpiryHeightOverride) +CTransaction MakeImportCoinTransaction(const ImportProof proof, const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride) { //std::vector payload = E_MARSHAL(ss << EVAL_IMPORTCOIN); CScript scriptSig; @@ -76,7 +76,7 @@ CTransaction MakeImportCoinTransaction(const ImportProof &proof, const CTransact } -CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string &targetSymbol, const std::vector &payouts, const std::vector &rawproof) +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string targetSymbol, const std::vector payouts, const std::vector rawproof) { std::vector opret; opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; // should mark burn opret to differentiate it from token opret @@ -91,7 +91,8 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb uint256 bindtxid,std::vector publishers,std::vector txids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount) { std::vector opret; - opret = E_MARSHAL(ss << VARINT(targetCCid); + opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; + ss << VARINT(targetCCid); ss << targetSymbol; ss << SerializeHash(payouts); ss << rawproof; @@ -112,7 +113,8 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb std::string receipt) { std::vector opret; - opret = E_MARSHAL(ss << VARINT(targetCCid); + opret = E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN; + ss << VARINT(targetCCid); ss << targetSymbol; ss << SerializeHash(payouts); ss << rawproof; @@ -122,7 +124,7 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb } -bool UnmarshalImportTx(const CTransaction &importTx, ImportProof &proof, CTransaction &burnTx, std::vector &payouts) +bool UnmarshalImportTx(const CTransaction importTx, ImportProof &proof, CTransaction &burnTx, std::vector &payouts) { if (importTx.vout.size() < 1) return false; @@ -173,7 +175,7 @@ bool UnmarshalImportTx(const CTransaction &importTx, ImportProof &proof, CTransa } -bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector&rawproof) +bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector&rawproof) { std::vector vburnOpret; uint32_t ccid = 0; uint8_t evalCode; @@ -211,8 +213,8 @@ bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint ss >> VARINT(*targetCCid); ss >> targetSymbol; ss >> payoutsHash; - ss >> rawproof; isEof = ss.eof();) || !isEof; // if isEof == false it means we successfully read add the data - // and it might be additional data further that we do not need here + ss >> rawproof; isEof = ss.eof();) || !isEof; // if isEof == false it means we have successfully read the vars upto 'rawproof' + // and it might be additional data further that we do not need here so we allow !isEof } else { LOGSTREAM("importcoin", CCLOG_INFO, stream << "UnmarshalBurnTx() invalid eval code in opret" << std::endl); @@ -220,14 +222,16 @@ bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &targetSymbol, uint } } -bool UnmarshalBurnTx(const CTransaction &burnTx, std::string &srcaddr, std::string &receipt) +bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt) { std::vector burnOpret,rawproof; bool isEof=true; std::string targetSymbol; uint32_t targetCCid; uint256 payoutsHash; + uint8_t evalCode; if (burnTx.vout.size() == 0) return false; GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); - return (E_UNMARSHAL(burnOpret, ss >> VARINT(targetCCid); + return (E_UNMARSHAL(burnOpret, ss >> evalCode; + ss >> VARINT(targetCCid); ss >> targetSymbol; ss >> payoutsHash; ss >> rawproof; @@ -239,10 +243,12 @@ bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector burnOpret,rawproof; bool isEof=true; uint32_t targetCCid; uint256 payoutsHash; std::string targetSymbol; + uint8_t evalCode; if (burnTx.vout.size() == 0) return false; GetOpReturnData(burnTx.vout.back().scriptPubKey, burnOpret); - return (E_UNMARSHAL(burnOpret, ss >> VARINT(targetCCid); + return (E_UNMARSHAL(burnOpret, ss >> evalCode; + ss >> VARINT(targetCCid); ss >> targetSymbol; ss >> payoutsHash; ss >> rawproof; diff --git a/src/importcoin.h b/src/importcoin.h index febf93d61..e016a7c52 100644 --- a/src/importcoin.h +++ b/src/importcoin.h @@ -94,9 +94,9 @@ public: CAmount GetCoinImportValue(const CTransaction &tx); -CTransaction MakeImportCoinTransaction(const ImportProof &proof, const CTransaction &burnTx, const std::vector &payouts, uint32_t nExpiryHeightOverride = 0); +CTransaction MakeImportCoinTransaction(const ImportProof proof, const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride = 0); -CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string &targetSymbol, const std::vector &payouts, const std::vector &rawproof); +CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, const std::string targetSymbol, const std::vector payouts, const std::vector rawproof); CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof, uint256 bindtxid,std::vector publishers,std::vectortxids,uint256 burntxid,int32_t height,int32_t burnvout,std::string rawburntx,CPubKey destpub, int64_t amount); CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymbol, const std::vector payouts,std::vector rawproof,std::string srcaddr, @@ -105,7 +105,7 @@ CTxOut MakeBurnOutput(CAmount value, uint32_t targetCCid, std::string targetSymb bool UnmarshalBurnTx(const CTransaction burnTx, std::string &targetSymbol, uint32_t *targetCCid, uint256 &payoutsHash,std::vector &rawproof); bool UnmarshalBurnTx(const CTransaction burnTx, std::string &srcaddr, std::string &receipt); bool UnmarshalBurnTx(const CTransaction burnTx,uint256 &bindtxid,std::vector &publishers,std::vector &txids,uint256& burntxid,int32_t &height,int32_t &burnvout,std::string &rawburntx,CPubKey &destpub, int64_t &amount); -bool UnmarshalImportTx(const CTransaction &importTx, ImportProof &proof, CTransaction &burnTx,std::vector &payouts); +bool UnmarshalImportTx(const CTransaction importTx, ImportProof &proof, CTransaction &burnTx,std::vector &payouts); bool VerifyCoinImport(const CScript& scriptSig, TransactionSignatureChecker& checker, CValidationState &state); @@ -116,6 +116,6 @@ int ExistsImportTombstone(const CTransaction &importTx, const CCoinsViewCache &i bool CheckVinPubKey(const CTransaction &sourcetx, int32_t i, uint8_t pubkey33[33]); CMutableTransaction MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount); -int32_t GetSelfimportProof(const CMutableTransaction &sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull); +int32_t GetSelfimportProof(const CMutableTransaction sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull); #endif /* IMPORTCOIN_H */ From 59a02a874e3e492ad494bbb63bcac3da478fe4df Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 19 Apr 2019 15:27:42 +0500 Subject: [PATCH 16/43] corr selfimport param --- src/cc/import.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/import.cpp b/src/cc/import.cpp index 913bf0295..674b024e3 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -119,7 +119,7 @@ bool CheckVinPubKey(const CTransaction &sourcetx, int32_t i, uint8_t pubkey33[33 // ac_import=PUBKEY support: // prepare a tx for creating import tx and quasi-burn tx -int32_t GetSelfimportProof(const CMutableTransaction &sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull) // find burnTx with hash from "other" daemon +int32_t GetSelfimportProof(const CMutableTransaction sourceMtx, CMutableTransaction &templateMtx, ImportProof &proofNull) // find burnTx with hash from "other" daemon { MerkleBranch newBranch; CMutableTransaction tmpmtx; From 19c49770569f6e6902e1a2ce1273e15aac31903f Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 19 Apr 2019 15:55:34 +0500 Subject: [PATCH 17/43] test invalid on --- src/cc/import.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cc/import.cpp b/src/cc/import.cpp index 674b024e3..675b9771e 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -521,7 +521,7 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti bool CheckMigration(Eval *eval, const CTransaction &importTx, const CTransaction &burnTx, std::vector & payouts, const ImportProof &proof, const std::vector &rawproof) { - if (strcmp(ASSETCHAINS_SYMBOL, "CFEKDIMXY6") == 0 && chainActive.Height() <= 10699) + if (strcmp(ASSETCHAINS_SYMBOL, "CFEKDIMXY6") == 0 && chainActive.Height() <= 44693) return true; vscript_t vimportOpret; @@ -641,6 +641,11 @@ bool CheckMigration(Eval *eval, const CTransaction &importTx, const CTransaction else { return eval->Invalid("invalid-import-proof"); } + + if (vimportOpret.begin()[0] == EVAL_TOKENS) + return eval->Invalid("test-invalid-tokens-are-good!!"); + else + return eval->Invalid("test-invalid-coins-are-good!!"); return true; } @@ -741,11 +746,6 @@ bool Eval::ImportCoin(const std::vector params, const CTransaction &imp // return Invalid("test-invalid"); LOGSTREAM("importcoin", CCLOG_DEBUG2, stream << "Valid import tx! txid=" << importTx.GetHash().GetHex() << std::endl); - - /*if (vimportOpret.begin()[0] == EVAL_TOKENS) - return Invalid("test-invalid-tokens-are-good!!"); - else - return Invalid("test-invalid-coins-are-good!!");*/ - + return Valid(); } From c3e7b1c799a06e2825ff3eec840b23759d44f581 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 19 Apr 2019 19:16:16 +0500 Subject: [PATCH 18/43] corr ret true for prev tx --- src/cc/import.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cc/import.cpp b/src/cc/import.cpp index 675b9771e..be8fbe502 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -521,9 +521,6 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti bool CheckMigration(Eval *eval, const CTransaction &importTx, const CTransaction &burnTx, std::vector & payouts, const ImportProof &proof, const std::vector &rawproof) { - if (strcmp(ASSETCHAINS_SYMBOL, "CFEKDIMXY6") == 0 && chainActive.Height() <= 44693) - return true; - vscript_t vimportOpret; if (!GetOpReturnData(importTx.vout.back().scriptPubKey, vimportOpret) || vimportOpret.empty()) @@ -666,6 +663,9 @@ bool Eval::ImportCoin(const std::vector params, const CTransaction &imp LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "Validating import tx..., txid=" << importTx.GetHash().GetHex() << std::endl); + if (strcmp(ASSETCHAINS_SYMBOL, "CFEKDIMXY6") == 0 && chainActive.Height() <= 44693) + return true; + if (importTx.vout.size() < 2) return Invalid("too-few-vouts"); // params From e2fc84faac4fdfb24a1cbddbe014ae80cc95c66c Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 19 Apr 2019 19:28:48 +0500 Subject: [PATCH 19/43] defined missing rpc createburntx --- src/rpc/server.cpp | 1 + src/rpc/server.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 1b6442865..3ed082455 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -352,6 +352,7 @@ static const CRPCCommand vRPCCommands[] = { "crosschain", "getimports", &getimports, true }, { "crosschain", "getwalletburntransactions", &getwalletburntransactions, true }, { "crosschain", "migrate_converttoexport", &migrate_converttoexport, true }, + { "crosschain", "migrate_createburntransaction", &migrate_createburntransaction, true }, { "crosschain", "migrate_createimporttransaction", &migrate_createimporttransaction, true }, { "crosschain", "migrate_completeimporttransaction", &migrate_completeimporttransaction, true }, { "crosschain", "migrate_checkburntransactionsource", &migrate_checkburntransactionsource, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index db8906f1f..8e0054e6f 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -480,6 +480,7 @@ extern UniValue scanNotarisationsDB(const UniValue& params, bool fHelp); extern UniValue getimports(const UniValue& params, bool fHelp); extern UniValue getwalletburntransactions(const UniValue& params, bool fHelp); extern UniValue migrate_converttoexport(const UniValue& params, bool fHelp); +extern UniValue migrate_createburntransaction(const UniValue& params, bool fHelp); extern UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp); extern UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp); extern UniValue migrate_checkburntransactionsource(const UniValue& params, bool fHelp); From b4175592e8c9c82d3abfbd90c9640fe2b30d3ed0 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Fri, 19 Apr 2019 18:41:58 +0200 Subject: [PATCH 20/43] Add -earlytxid param and check -ac_end,-ac_supply and -ac_perc. (#23) --- src/cc/CCImportGateway.h | 2 +- src/cc/import.cpp | 6 ++++++ src/cc/importgateway.cpp | 13 ++++++++++--- src/komodo_globals.h | 2 +- src/komodo_utils.h | 8 +++++++- src/rpc/crosschain.cpp | 9 +++++---- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/cc/CCImportGateway.h b/src/cc/CCImportGateway.h index 995cde460..671b431cd 100644 --- a/src/cc/CCImportGateway.h +++ b/src/cc/CCImportGateway.h @@ -23,7 +23,7 @@ bool ImportGatewayValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx, uint32_t nIn); bool ImportGatewayExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid); std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4); -std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t burnvout,std::string rawburntx,std::vectorproof,CPubKey destpub); +std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t burnvout,std::string rawburntx,std::vectorproof,CPubKey destpub,int64_t amount); std::string ImportGatewayWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount); std::string ImportGatewayPartialSign(uint64_t txfee,uint256 lasttxid,std::string refcoin, std::string hex); std::string ImportGatewayCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string refcoin,std::string hex); diff --git a/src/cc/import.cpp b/src/cc/import.cpp index ea22f5e42..ebdeee235 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -27,6 +27,7 @@ extern std::string ASSETCHAINS_SELFIMPORT; extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT; extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; +extern uint256 KOMODO_EARLYTXID; // utilities from gateways.cpp uint256 BitcoinGetProofMerkleRoot(const std::vector &proofData, std::vector &txids); @@ -339,6 +340,11 @@ int32_t CheckGATEWAYimport(CTransaction importTx,CTransaction burnTx,std::string std::vector > unspentOutputs; // ASSETCHAINS_SELFIMPORT is coin + if (KOMODO_EARLYTXID!=zeroid && bindtxid!=KOMODO_EARLYTXID) + { + LOGSTREAM("importgateway", CCLOG_INFO, stream << "CheckGATEWAYimport invalid import gateway. On this chain only valid import gateway is " << KOMODO_EARLYTXID.GetHex() << std::endl); + return(-1); + } // check for valid burn from external coin blockchain and if valid return(0); if (GetTransaction(bindtxid, bindtx, hashBlock, false) == 0 || (numvouts = bindtx.vout.size()) <= 0) { diff --git a/src/cc/importgateway.cpp b/src/cc/importgateway.cpp index c3d318ca5..eff7bc287 100644 --- a/src/cc/importgateway.cpp +++ b/src/cc/importgateway.cpp @@ -25,6 +25,8 @@ #define KMD_TADDR 0 #define CC_MARKER_VALUE 10000 +extern uint256 KOMODO_EARLYTXID; + CScript EncodeImportGatewayBindOpRet(uint8_t funcid,std::string coin,uint256 oracletxid,uint8_t M,uint8_t N,std::vector importgatewaypubkeys,uint8_t taddr,uint8_t prefix,uint8_t prefix2,uint8_t wiftype) { CScript opret; uint8_t evalcode = EVAL_IMPORTGATEWAY; @@ -557,13 +559,19 @@ std::string ImportGatewayBind(uint64_t txfee,std::string coin,uint256 oracletxid return(""); } -std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t claimvout,std::string rawburntx,std::vectorproof,CPubKey destpub) +std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 burntxid,int32_t claimvout,std::string rawburntx,std::vectorproof,CPubKey destpub,int64_t amount) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()), burntx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CTransaction bindtx; CPubKey mypk; uint256 oracletxid,merkleroot,mhash,hashBlock,txid; std::vector vouts; int32_t i,m,n,numvouts; uint8_t M,N,taddr,prefix,prefix2,wiftype; std::string coin; struct CCcontract_info *cp,C; - std::vector pubkeys,publishers; std::vector txids; char str[128],burnaddr[64]; int64_t amount; + std::vector pubkeys,publishers; std::vector txids; char str[128],burnaddr[64]; + if (KOMODO_EARLYTXID!=zeroid && bindtxid!=KOMODO_EARLYTXID) + { + CCerror = strprintf("CheckGATEWAYimport invalid import gateway. On this chain only valid import gateway is %s",KOMODO_EARLYTXID.GetHex()); + LOGSTREAM("importgateway",CCLOG_INFO, stream << CCerror << std::endl); + return(""); + } cp = CCinit(&C,EVAL_IMPORTGATEWAY); if ( txfee == 0 ) txfee = 10000; @@ -572,7 +580,6 @@ std::string ImportGatewayDeposit(uint64_t txfee,uint256 bindtxid,int32_t height, { return std::string(""); } - amount=burntx.vout[0].nValue; LOGSTREAM("importgateway",CCLOG_DEBUG1, stream << "ImportGatewayDeposit ht." << height << " " << refcoin << " " << (double)amount/COIN << " numpks." << (int32_t)pubkeys.size() << std::endl); if ( GetTransaction(bindtxid,bindtx,hashBlock,false) == 0 || (numvouts= bindtx.vout.size()) <= 0 ) { diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 1ba137edc..6070e9326 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -44,7 +44,7 @@ struct komodo_state KOMODO_STATES[34]; #define _COINBASE_MATURITY 100 int COINBASE_MATURITY = _COINBASE_MATURITY;//100; unsigned int WITNESS_CACHE_SIZE = _COINBASE_MATURITY+10; - +uint256 KOMODO_EARLYTXID; int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,IS_STAKED_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,STAKED_ERA,KOMODO_CONNECTING = -1,KOMODO_DEALERNODE,KOMODO_EXTRASATOSHI,ASSETCHAINS_FOUNDERS; int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1; std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,NOTARY_ADDRESS,ASSETCHAINS_SELFIMPORT,ASSETCHAINS_CCLIB; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index d87b50716..4a1080cc1 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1756,6 +1756,7 @@ void komodo_args(char *argv0) { printf("KOMODO_REWIND %d\n",KOMODO_REWIND); } + KOMODO_EARLYTXID = Parseuint256(GetArg("-earlytxid","0").c_str()); if ( name.c_str()[0] != 0 ) { std::string selectedAlgo = GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0])); @@ -1932,7 +1933,12 @@ void komodo_args(char *argv0) StartShutdown(); } // else it can be gateway coin - + else if (!ASSETCHAINS_SELFIMPORT.empty() && (ASSETCHAINS_ENDSUBSIDY[0]!=1 || ASSETCHAINS_SUPPLY>10 || ASSETCHAINS_COMMISSION!=0)) + { + fprintf(stderr,"when using gateway import these must be set: -ac_end=1 -ac_supply=0 -ac_perc=0\n"); + StartShutdown(); + } + if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 ) ASSETCHAINS_STAKED = 100; diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index cacf4357e..5cdaa7fe8 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -541,13 +541,13 @@ UniValue importgatewaydeposit(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); CMutableTransaction mtx; std::vector rawproof; - std::string hex,coin,rawburntx; int32_t height,burnvout; + std::string hex,coin,rawburntx; int32_t height,burnvout; int64_t amount; CPubKey destpub; std::vector vouts; uint256 bindtxid,burntxid; if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) throw runtime_error("importgatewaydeposit only works on -ac_import chains"); - if ( fHelp || params.size() != 8) - throw runtime_error("use \'importgatewaydeposit bindtxid height coin burntxid nvout rawburntx rawproof destpub\' to import deposited coins\n"); + if ( fHelp || params.size() != 9) + throw runtime_error("use \'importgatewaydeposit bindtxid height coin burntxid nvout rawburntx rawproof destpub amount\' to import deposited coins\n"); if ( ensure_CCrequirements(EVAL_IMPORTGATEWAY) < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); CCerror = ""; @@ -559,6 +559,7 @@ UniValue importgatewaydeposit(const UniValue& params, bool fHelp) rawburntx = params[5].get_str(); rawproof = ParseHex(params[6].get_str()); destpub = ParseHex(params[7].get_str()); + amount = atof(params[8].get_str().c_str()) * COIN + 0.00000000499999; if (coin == "BEAM" || coin == "CODA") { ERR_RESULT("for BEAM and CODA import use importdual RPC"); @@ -569,7 +570,7 @@ UniValue importgatewaydeposit(const UniValue& params, bool fHelp) ERR_RESULT("source coin not equal to ac_import name"); return result; } - hex = ImportGatewayDeposit(0, bindtxid, height, coin, burntxid, burnvout, rawburntx, rawproof, destpub); + hex = ImportGatewayDeposit(0, bindtxid, height, coin, burntxid, burnvout, rawburntx, rawproof, destpub, amount); RETURN_IF_ERROR(CCerror); if ( hex.size() > 0 ) { From fa9ca8b430919b7c7bf632576b60337dbda87b88 Mon Sep 17 00:00:00 2001 From: dimxy Date: Fri, 19 Apr 2019 23:07:12 +0500 Subject: [PATCH 21/43] removed test invalid return --- src/cc/import.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/import.cpp b/src/cc/import.cpp index be8fbe502..347724006 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -639,10 +639,10 @@ bool CheckMigration(Eval *eval, const CTransaction &importTx, const CTransaction return eval->Invalid("invalid-import-proof"); } - if (vimportOpret.begin()[0] == EVAL_TOKENS) +/* if (vimportOpret.begin()[0] == EVAL_TOKENS) return eval->Invalid("test-invalid-tokens-are-good!!"); else - return eval->Invalid("test-invalid-coins-are-good!!"); + return eval->Invalid("test-invalid-coins-are-good!!"); */ return true; } From 03794dc2087785e630e5e8c9b226312631ff812a Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Fri, 19 Apr 2019 21:57:10 +0300 Subject: [PATCH 22/43] first approach to get HTTPS in libcurl work 1. libcurl.mk now changed to build against static openssl from deps. 2. but, it won't work with openssl 1.1.1a, bcz of SSL: couldn't create a context: error:00000000:lib(0):func(0):reason(0) , so, in test i decided to upgrade openssl to 1.1.1b. 3. original openssl.mk was with many disabled features, i enable all of them, of course it's don't needed and we need to leave only SSL/TLS things enabled in OpenSSL build. 4. probably i broke something in Windows and MacOS build. This commit is only first approach to continue work. --- depends/packages/libcurl.mk | 23 +++++++++--- depends/packages/openssl.mk | 72 +----------------------------------- depends/packages/packages.mk | 2 +- 3 files changed, 21 insertions(+), 76 deletions(-) diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 642fc066d..1ce0a9161 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -1,9 +1,10 @@ package=libcurl -$(package)_version=7.54.0 +$(package)_version=7.64.1 +$(package)_dependencies=openssl $(package)_download_path=https://curl.haxx.se/download $(package)_file_name=curl-$($(package)_version).tar.gz -$(package)_sha256_hash=a84b635941c74e26cce69dd817489bec687eb1f230e7d1897fc5b5f108b59adf -$(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) +$(package)_sha256_hash=432d3f466644b9416bc5b649d344116a753aeaa520c8beaf024a90cba9d3d35d +$(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) --host=x86_64-unknown-linux-gnu $(package)_config_opts_mingw32=--enable-mingw --disable-shared --enable-static --prefix=$(host_prefix) --host=x86_64-w64-mingw32 $(package)_config_opts_darwin=--disable-shared --enable-static --prefix=$(host_prefix) $(package)_cflags_darwin=-mmacosx-version-min=10.9 @@ -15,11 +16,21 @@ define $(package)_set_vars endef endif -define $(package)_config_cmds - $($(package)_conf_tool) $($(package)_config_opts) +ifeq ($(build_os),linux) +define $(package)_set_vars + $(package)_config_env=LD_LIBRARY_PATH="$(host_prefix)/lib" PKG_CONFIG_LIBDIR="$(host_prefix)/lib/pkgconfig" CPPFLAGS="-I$(host_prefix)/include" LDFLAGS="-L$(host_prefix)/lib" endef +endif +define $(package)_config_cmds + echo '=== config for $(package):' && \ + echo '$($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts)' && \ + sleep 10 && \ + echo '=== ' && \ + $($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts) +endef + ifeq ($(build_os),darwin) define $(package)_build_cmds $(MAKE) CPPFLAGS='-fPIC' CFLAGS='-mmacosx-version-min=10.9' @@ -31,5 +42,7 @@ endef endif define $(package)_stage_cmds + echo 'Staging dir: $($(package)_staging_dir)$(host_prefix)/' && \ + sleep 10 && \ $(MAKE) DESTDIR=$($(package)_staging_dir) install endef diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index e378088e6..96908e151 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,81 +1,13 @@ package=openssl -$(package)_version=1.1.1a +$(package)_version=1.1.1b $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41 +$(package)_sha256_hash=5c557b023230413dfb0756f3137a13e6d726838ccd1430888ad15bfb2b43ea4b define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl -$(package)_config_opts+=no-afalgeng -$(package)_config_opts+=no-asm -$(package)_config_opts+=no-async -$(package)_config_opts+=no-bf -$(package)_config_opts+=no-blake2 -$(package)_config_opts+=no-camellia -$(package)_config_opts+=no-capieng -$(package)_config_opts+=no-cast -$(package)_config_opts+=no-chacha -$(package)_config_opts+=no-cmac -$(package)_config_opts+=no-cms -$(package)_config_opts+=no-comp -$(package)_config_opts+=no-crypto-mdebug -$(package)_config_opts+=no-crypto-mdebug-backtrace -$(package)_config_opts+=no-ct -$(package)_config_opts+=no-des -$(package)_config_opts+=no-dgram -$(package)_config_opts+=no-dsa -$(package)_config_opts+=no-dso -$(package)_config_opts+=no-dtls -$(package)_config_opts+=no-dtls1 -$(package)_config_opts+=no-dtls1-method -$(package)_config_opts+=no-dynamic-engine -$(package)_config_opts+=no-ec2m -$(package)_config_opts+=no-ec_nistp_64_gcc_128 -$(package)_config_opts+=no-egd -$(package)_config_opts+=no-engine -$(package)_config_opts+=no-err -$(package)_config_opts+=no-gost -$(package)_config_opts+=no-heartbeats -$(package)_config_opts+=no-idea -$(package)_config_opts+=no-md2 -$(package)_config_opts+=no-md4 -$(package)_config_opts+=no-mdc2 -$(package)_config_opts+=no-multiblock -$(package)_config_opts+=no-nextprotoneg -$(package)_config_opts+=no-ocb -$(package)_config_opts+=no-ocsp -$(package)_config_opts+=no-poly1305 -$(package)_config_opts+=no-posix-io -$(package)_config_opts+=no-psk -$(package)_config_opts+=no-rc2 -$(package)_config_opts+=no-rc4 -$(package)_config_opts+=no-rc5 -$(package)_config_opts+=no-rdrand -$(package)_config_opts+=no-rfc3779 -$(package)_config_opts+=no-rmd160 -$(package)_config_opts+=no-scrypt -$(package)_config_opts+=no-sctp -$(package)_config_opts+=no-seed $(package)_config_opts+=no-shared -$(package)_config_opts+=no-sock -$(package)_config_opts+=no-srp -$(package)_config_opts+=no-srtp -$(package)_config_opts+=no-ssl -$(package)_config_opts+=no-ssl3 -$(package)_config_opts+=no-ssl3-method -$(package)_config_opts+=no-ssl-trace -$(package)_config_opts+=no-stdio -$(package)_config_opts+=no-tls -$(package)_config_opts+=no-tls1 -$(package)_config_opts+=no-tls1-method -$(package)_config_opts+=no-ts -$(package)_config_opts+=no-ui -$(package)_config_opts+=no-unit-test -$(package)_config_opts+=no-weak-ssl-ciphers -$(package)_config_opts+=no-whirlpool -$(package)_config_opts+=no-zlib -$(package)_config_opts+=no-zlib-dynamic $(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) $(package)_config_opts+=-DPURIFY $(package)_config_opts_linux=-fPIC -Wa,--noexecstack diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 5bc8fcda6..e29c62580 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -47,7 +47,7 @@ native_packages := native_ccache wallet_packages=bdb ifeq ($(host_os),linux) - packages := boost openssl libevent zeromq $(zcash_packages) googletest #googlemock + packages := boost openssl libevent zeromq $(zcash_packages) googletest libcurl #googlemock else packages := boost openssl libevent zeromq $(zcash_packages) libcurl googletest #googlemock endif From 2f19aeaa4adab8c5462b76ef65f93e0fd1c0e204 Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Fri, 19 Apr 2019 22:01:54 +0300 Subject: [PATCH 23/43] + debug (ssl and curl version printout) --- src/komodo_bitcoind.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index bb5a093d3..92943089a 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -206,8 +206,11 @@ try_again: if ( strncmp(url,"https",5) == 0 ) { - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); + + /* printf("[ Decker ] SSL: %s\n", curl_version()); */ + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + //curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); // this is useful for debug, but seems crash on libcurl/7.64.1 OpenSSL/1.1.1b zlib/1.2.8 librtmp/2.3 } if ( userpass != 0 ) curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); From fea2b66581b9a6fbcfed431e91a6c6ee97fb70ea Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sat, 20 Apr 2019 19:29:16 +0800 Subject: [PATCH 24/43] add validation for OP_RETURN to payments CC. Enable ccvoutopret for payments fund. --- src/cc/CCinclude.h | 7 +++- src/cc/CCutils.cpp | 53 ++++++++++++++++++++----- src/cc/customcc.cpp | 32 +++++---------- src/cc/payments.cpp | 96 +++++++++++++++++++++++++++++++++++---------- 4 files changed, 135 insertions(+), 53 deletions(-) diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 5a515634d..db1ee7475 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -226,8 +226,11 @@ bool priv2addr(char *coinaddr,uint8_t buf33[33],uint8_t priv32[32]); CPubKey buf2pk(uint8_t *buf33); void endiancpy(uint8_t *dest,uint8_t *src,int32_t len); uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout); -CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, const std::vector>* vData = NULL); -CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, const std::vector>* vData = NULL); +CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk, std::vector>* vData = NULL); +CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2, std::vector>* vData = NULL); +int32_t has_opret(const CTransaction &tx, uint8_t evalcode); +CScript getCCopret(const CScript &scriptPubKey); +bool makeCCopret(CScript &opret, std::vector> &vData); CC *MakeCCcond1(uint8_t evalcode,CPubKey pk); CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2); CC* GetCryptoCondition(CScript const& scriptSig); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index e9acfbe20..b563bd09a 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -58,35 +58,70 @@ CC *MakeCCcond1(uint8_t evalcode,CPubKey pk) return CCNewThreshold(2, {condCC, Sig}); } -CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, const std::vector>* vData) +int32_t has_opret(const CTransaction &tx, uint8_t evalcode) +{ + int i = 0; + for ( auto vout : tx.vout ) + { + if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode ) + return i; + i++; + } + return 0; +} + +CScript getCCopret(const CScript &scriptPubKey) +{ + std::vector> vParams = std::vector>(); + CScript dummy; CScript opret; + if ( scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) ) + { + //opret << E_MARSHAL(ss << vParams[0]); + opret = CScript(vParams[0].begin()+6, vParams[0].end()); + } + //fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vParams.size(), HexStr(vParams[0].begin(),vParams[0].end()).c_str()); + //opret = CScript(vParams[0].begin(), vParams[0].end()); + return opret; +} + +bool makeCCopret(CScript &opret, std::vector> &vData) +{ + if ( opret.empty() ) + return false; + vData.push_back(std::vector(opret.begin(), opret.end())); + return true; +} + +CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue, CPubKey pk, std::vector>* vData) { CTxOut vout; CC *payoutCond = MakeCCcond1(evalcode,pk); vout = CTxOut(nValue,CCPubKey(payoutCond)); if ( vData ) { - std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); + //std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); std::vector vPubKeys = std::vector(); - vPubKeys.push_back(pk); - COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, vtmpData); + //vPubKeys.push_back(pk); + COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 1, vPubKeys, ( * vData)); vout.scriptPubKey << ccp.AsVector() << OP_DROP; } cc_free(payoutCond); return(vout); } -CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, const std::vector>* vData) +CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2, std::vector>* vData) { CTxOut vout; CC *payoutCond = MakeCCcond1of2(evalcode,pk1,pk2); vout = CTxOut(nValue,CCPubKey(payoutCond)); if ( vData ) { - std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); + //std::vector> vtmpData = std::vector>(vData->begin(), vData->end()); std::vector vPubKeys = std::vector(); - vPubKeys.push_back(pk1); - vPubKeys.push_back(pk2); - COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, vtmpData); + // skip pubkeys. These need to maybe be optional and we need some way to get them out that is easy! + //vPubKeys.push_back(pk1); + //vPubKeys.push_back(pk2); + COptCCParams ccp = COptCCParams(COptCCParams::VERSION, evalcode, 1, 2, vPubKeys, ( * vData)); vout.scriptPubKey << ccp.AsVector() << OP_DROP; } cc_free(payoutCond); diff --git a/src/cc/customcc.cpp b/src/cc/customcc.cpp index 2e174f510..a8b0bf871 100644 --- a/src/cc/customcc.cpp +++ b/src/cc/customcc.cpp @@ -67,38 +67,26 @@ UniValue custom_func1(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) // make op_return payload as normal. CScript opret = custom_opret('1',mypk); std::vector> vData = std::vector>(); - vData.push_back(std::vector(opret.begin(), opret.end())); - // make vout0 with op_return included as payload. - mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData)); - fprintf(stderr, "vout size2.%li\n", mtx.vout.size()); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript()); - return(custom_rawtxresult(result,rawtx,broadcastflag)); + if ( makeCCopret(opret, vData) ) + { + // make vout0 with op_return included as payload. + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,mypk,&vData)); + fprintf(stderr, "vout size2.%li\n", mtx.vout.size()); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript()); + return(custom_rawtxresult(result,rawtx,broadcastflag)); + } } return(result); } -bool has_opret(const CTransaction &tx, uint8_t evalcode) -{ - for ( auto vout : tx.vout ) - { - if ( vout.scriptPubKey[0] == OP_RETURN && vout.scriptPubKey[1] == evalcode ) - return true; - } - return false; -} - bool custom_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { char expectedaddress[64]; CPubKey pk; CScript opret; int32_t numvout; - if ( !has_opret(tx, EVAL_CUSTOM) ) + if ( has_opret(tx, EVAL_CUSTOM) == 0 ) { std::vector> vParams = std::vector>(); - CScript dummy; - if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition(&dummy, vParams) && vParams.size() == 1 ) - { - opret << E_MARSHAL(ss << vParams[0]); - } + opret = getCCopret(tx.vout[0].scriptPubKey); numvout = 1; } else diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index d83cd0bec..3e4666f47 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -16,6 +16,12 @@ #include "CCPayments.h" /* + +-earlytxid is not an -ac_param, so it doesnt affect the chain magics +extra data after the normal CCvout is whatever data we want and can represent whatever we want +so -ac_script= +in the validation if you see the useearlytxid in the opreturn data or extra data, you use the earlytxid as the txid that specifies the payment + 0) txidopret <- allocation, scriptPubKey, opret 1) create <- locked_blocks, minrelease, list of txidopret @@ -212,6 +218,20 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & allocations.push_back(allocation); //fprintf(stderr, "i.%i scriptpubkey.%s allocation.%li\n",i,scriptPubKeys[i].ToString().c_str(),allocation); checkallocations += allocation; + // if we have an op_return to pay to need to check it exists and is paying the correct opret. + if ( !opret.empty() ) + { + if ( !fHasOpret ) + { + fprintf(stderr, "missing opret.%s in payments release.\n",HexStr(opret.begin(), opret.end()).c_str()); + return(eval->Invalid("missing opret in payments release")); + } + else if ( CScript(opret.begin(),opret.end()) != tx.vout[tx.vout.size()-1].scriptPubKey ) + { + fprintf(stderr, "opret.%s vs opret.%s\n",HexStr(opret.begin(), opret.end()).c_str(), HexStr(tx.vout[tx.vout.size()-1].scriptPubKey.begin(), tx.vout[tx.vout.size()-1].scriptPubKey.end()).c_str()); + return(eval->Invalid("pays incorrect opret")); + } + } } i++; } @@ -277,14 +297,24 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & Getscriptaddress(destaddr,txin.vout[vin.prevout.n].scriptPubKey); if ( strcmp(destaddr,coinaddr) != 0 ) { - std::vector scriptPubKey,opret; uint256 checktxid; - if ( txin.vout.size() < 2 || DecodePaymentsFundOpRet(txin.vout[txin.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid ) + CScript opret; uint256 checktxid; int32_t opret_ind; + if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) + { + // get op_return from CCvout + opret = getCCopret(txin.vout[0].scriptPubKey); + } + else + { + // get op_return from the op_return + opret = txin.vout[opret_ind].scriptPubKey; + } // else return(eval->Invalid("vin has wrong amount of vouts")); // dont think this is needed? + if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); return(eval->Invalid("vin is not paymentsCC type")); - } //else fprintf(stderr, "vin.%i opret type txid.%s\n", i, txin.GetHash().ToString().c_str()); + } } - // check the chain depth vs locked blcoks requirement. + // check the chain depth vs locked blocks requirement. CBlockIndex* pblockindex = mapBlockIndex[blockhash]; if ( pblockindex->GetHeight() > ht-lockedblocks ) { @@ -340,8 +370,18 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP } if ( iter == 0 ) { - std::vector scriptPubKey,opret; - if ( myGetTransaction(txid,tx,hashBlock) == 0 || tx.vout.size() < 2 || DecodePaymentsFundOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,checktxid) != 'F' || checktxid != createtxid ) + CScript opret; uint256 checktxid; int32_t opret_ind; + if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 ) + { + // get op_return from CCvout + opret = getCCopret(vintx.vout[0].scriptPubKey); + } + else + { + // get op_return from the op_return + opret = vintx.vout[opret_ind].scriptPubKey; + } + if ( myGetTransaction(txid,tx,hashBlock) == 0 || DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str()); continue; @@ -603,10 +643,16 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) } else { - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); opret = EncodePaymentsFundOpRet(txid); + fprintf(stderr, "opret.%s\n", HexStr(opret.begin(), opret.end()).c_str()); + std::vector> vData = std::vector>(); + if ( makeCCopret(opret, vData) ) + { + mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); + fprintf(stderr, "params_size.%li parmas_hexstr.%s\n", vData.size(), HexStr(vData[0].begin(),vData[0].end()).c_str()); + } } - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,opret); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); if ( params != 0 ) free_json(params); return(payments_rawtxresult(result,rawtx,1)); @@ -630,24 +676,34 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) UniValue PaymentsTxidopret(struct CCcontract_info *cp,char *jsonstr) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); UniValue result(UniValue::VOBJ); CPubKey mypk; std::string rawtx; - std::vector scriptPubKey,opret; int32_t allocation,n,retval0,retval1=0; + std::vector scriptPubKey,opret; int32_t n,retval0,retval1=0; int64_t allocation; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); if ( params != 0 && n > 1 && n <= 3 ) { - allocation = juint(jitem(params,0),0); + allocation = (int64_t)jint(jitem(params,0),0); retval0 = payments_parsehexdata(scriptPubKey,jitem(params,1),0); - if ( n == 3 ) - retval1 = payments_parsehexdata(opret,jitem(params,2),0); - if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE,10) > 0 ) + CScript test = CScript(scriptPubKey.begin(),scriptPubKey.end()); + txnouttype whichType; + if (!::IsStandard(test, whichType)) { - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret)); - if ( params != 0 ) - free_json(params); - return(payments_rawtxresult(result,rawtx,1)); + result.push_back(Pair("result","error")); + result.push_back(Pair("error","scriptPubkey is not valid payment.")); + } + else + { + if ( n == 3 ) + retval1 = payments_parsehexdata(opret,jitem(params,2),0); + if ( allocation > 0 && retval0 == 0 && retval1 == 0 && AddNormalinputs(mtx,mypk,PAYMENTS_TXFEE*2,10) > 0 ) + { + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsTxidOpRet(allocation,scriptPubKey,opret)); + if ( params != 0 ) + free_json(params); + return(payments_rawtxresult(result,rawtx,1)); + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid params or cant find txfee")); } - result.push_back(Pair("result","error")); - result.push_back(Pair("error","invalid params or cant find txfee")); } else { @@ -867,7 +923,7 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) funds = CCaddress_balance(fundsaddr,1); result.push_back(Pair(fundsaddr,ValueFromAmount(funds))); GetCCaddress(cp,fundsopretaddr,Paymentspk); - fundsopret = CCaddress_balance(fundsopretaddr,1); + fundsopret = CCaddress_balance(fundsopretaddr,1); // Shows balance for ALL payments plans, not just the one asked for! result.push_back(Pair(fundsopretaddr,ValueFromAmount(fundsopret))); result.push_back(Pair("totalfunds",ValueFromAmount(funds+fundsopret))); result.push_back(Pair("result","success")); From 82e6cd0f935e934eedafcb3fad554e4c86dc1793 Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sun, 21 Apr 2019 11:48:16 +0800 Subject: [PATCH 25/43] fix two bugs for Alright --- src/cc/CCutils.cpp | 6 +++++- src/cc/payments.cpp | 9 ++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index b563bd09a..3c4c6c67c 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -149,8 +149,12 @@ bool IsCCInput(CScript const& scriptSig) bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime) { + LOCK(mempool.cs); + CCoinsView dummy; + CCoinsViewCache view(&dummy); int64_t interest; uint64_t valuein; - CCoinsViewCache &view = *pcoinsTip; + CCoinsViewMemPool viewMemPool(pcoinsTip, mempool); + view.SetBackend(viewMemPool); valuein = view.GetValueIn(height,&interest,tx,blocktime); if ( valuein-tx.GetValueOut() > txfee ) { diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 3e4666f47..526fea52f 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -199,11 +199,10 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) return(eval->Invalid("negative values")); - if ( !CheckTxFee(tx, PAYMENTS_TXFEE, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) - return eval->Invalid("txfee is too high"); Paymentspk = GetUnspendable(cp,0); //fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() ); - + if ( !CheckTxFee(tx, PAYMENTS_TXFEE+1, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + return eval->Invalid("txfee is too high"); // Get all the script pubkeys and allocations std::vector allocations; std::vector scriptPubKeys; @@ -267,7 +266,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & int64_t test = allocations[n]; test *= checkamount; test /= totalallocations; - if ( test != tx.vout[i].nValue ) + if ( test != tx.vout[i].nValue && test != tx.vout[i].nValue-1 ) { fprintf(stderr, "vout.%i test.%li vs nVlaue.%li\n",i, test, tx.vout[i].nValue); return(eval->Invalid("amounts do not match")); @@ -564,7 +563,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) newamount += (PAYMENTS_TXFEE - mtx.vout[i+1].nValue); mtx.vout[i+1].nValue = PAYMENTS_TXFEE; } - } + } if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE ) { std::string rawtx; From d16cdf5538e349e72ba537c1c2f7626a2715479d Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sun, 21 Apr 2019 13:05:39 +0800 Subject: [PATCH 26/43] Add -testmode command line arg --- src/chainparams.cpp | 2 ++ src/chainparams.h | 1 + src/komodo_defs.h | 1 + src/komodo_globals.h | 2 ++ src/komodo_utils.h | 1 + src/wallet-utility.cpp | 1 + 6 files changed, 8 insertions(+) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index b09ccf7c3..b8b2998b7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -289,6 +289,8 @@ void *chainparams_commandline(void *ptr) mainParams.SetNValue(ASSETCHAINS_NK[0]); mainParams.SetKValue(ASSETCHAINS_NK[1]); } + if ( KOMODO_TESTNODE != 0 ) + mainParams.SetMiningRequiresPeers(false); if ( ASSETCHAINS_RPCPORT == 0 ) ASSETCHAINS_RPCPORT = ASSETCHAINS_P2PPORT + 1; mainParams.pchMessageStart[0] = ASSETCHAINS_MAGIC & 0xff; diff --git a/src/chainparams.h b/src/chainparams.h index 3b1ad1f72..daa16af8c 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -121,6 +121,7 @@ public: void SetCheckpointData(CCheckpointData checkpointData); void SetNValue(uint64_t n) { nEquihashN = n; } void SetKValue(uint64_t k) { nEquihashK = k; } + void SetMiningRequiresPeers(bool flag) { fMiningRequiresPeers = flag; } //void setnonce(uint32_t nonce) { memcpy(&genesis.nNonce,&nonce,sizeof(nonce)); } //void settimestamp(uint32_t timestamp) { genesis.nTime = timestamp; } diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 964ec852d..ecaf7339a 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -78,6 +78,7 @@ extern std::string DONATION_PUBKEY; extern uint8_t ASSETCHAINS_PRIVATE; extern int32_t USE_EXTERNAL_PUBKEY; extern char NOTARYADDRS[64][64]; +extern int32_t KOMODO_TESTNODE; int tx_height( const uint256 &hash ); extern std::vector vWhiteListAddress; void komodo_netevent(std::vector payload); diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 6070e9326..dc8cbda35 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -109,6 +109,8 @@ uint64_t PENDING_KOMODO_TX; extern int32_t KOMODO_LOADINGBLOCKS; unsigned int MAX_BLOCK_SIGOPS = 20000; +int32_t KOMODO_TESTNODE; + struct komodo_kv *KOMODO_KV; pthread_mutex_t KOMODO_KV_mutex,KOMODO_CC_mutex; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 4a1080cc1..88efb0264 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1710,6 +1710,7 @@ void komodo_args(char *argv0) DONATION_PUBKEY = GetArg("-donation", ""); NOTARY_PUBKEY = GetArg("-pubkey", ""); KOMODO_DEALERNODE = GetArg("-dealer",0); + KOMODO_TESTNODE = GetArg("-testnode",0); if ( strlen(NOTARY_PUBKEY.c_str()) == 66 ) { decode_hex(NOTARY_PUBKEY33,33,(char *)NOTARY_PUBKEY.c_str()); diff --git a/src/wallet-utility.cpp b/src/wallet-utility.cpp index 655a3cab4..0b664ecb3 100644 --- a/src/wallet-utility.cpp +++ b/src/wallet-utility.cpp @@ -24,6 +24,7 @@ int32_t ASSETCHAINS_LWMAPOS = 0; int32_t VERUS_BLOCK_POSUNITS = 1000; int32_t ASSETCHAINS_OVERWINTER = 227520; int32_t ASSETCHAINS_SAPLING = 227520; +int32_t KOMODO_TESTNODE = 0; unsigned int MAX_BLOCK_SIGOPS = 20000; From 06bed214f9af422fbc72dad021290761d6c3e315 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:16:55 -1100 Subject: [PATCH 27/43] Check for null ptr before -> --- src/komodo_bitcoind.h | 11 +++++++++++ src/komodo_defs.h | 1 + src/wallet/asyncrpcoperation_mergetoaddress.cpp | 2 +- src/wallet/asyncrpcoperation_sendmany.cpp | 2 +- src/wallet/rpcwallet.cpp | 6 +++--- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index bb5a093d3..b342cc932 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1091,6 +1091,17 @@ int32_t komodo_blockheight(uint256 hash) return(0); } +uint32_t komodo_blocktime(uint256 hash) +{ + BlockMap::const_iterator it; CBlockIndex *pindex = 0; + if ( (it = mapBlockIndex.find(hash)) != mapBlockIndex.end() ) + { + if ( (pindex= it->second) != 0 ) + return(pindex->nTime); + } + return(0); +} + int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 hash) { int32_t notarized_height,MoMdepth; uint256 MoM,notarized_hash,notarized_desttxid; CBlockIndex *notary,*pindex; diff --git a/src/komodo_defs.h b/src/komodo_defs.h index ecaf7339a..ee44132bc 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -95,6 +95,7 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160, int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width); int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen); +uint32_t komodo_blocktime(uint256 hash); int32_t komodo_longestchain(); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); int8_t komodo_segid(int32_t nocache,int32_t height); diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index bba44fe50..e5ce59a17 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -677,7 +677,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString())); } - wtxHeight = mapBlockIndex[wtx.hashBlock]->GetHeight(); + wtxHeight = komodo_blockheight(wtx.hashBlock); wtxDepth = wtx.GetDepthInMainChain(); } LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 0ea17a5f8..45d61b885 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -836,7 +836,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) { throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString())); } - wtxHeight = mapBlockIndex[wtx.hashBlock]->GetHeight(); + wtxHeight = komodo_blockheight(wtx.hashBlock); wtxDepth = wtx.GetDepthInMainChain(); } LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 847205ec1..028b18861 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -122,10 +122,10 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("generated", true)); if (confirms > 0) { - entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)mapBlockIndex[wtx.hashBlock]->GetHeight(),confirms))); + entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)komodo_blockheight(wtx.hashBlock),confirms))); entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + entry.push_back(Pair("blocktime", komodo_blocktime(wtx.hashBlock))); entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight)); } else entry.push_back(Pair("confirmations", confirms)); uint256 hash = wtx.GetHash(); @@ -1624,7 +1624,7 @@ UniValue ListReceived(const UniValue& params, bool fByAccounts) tallyitem& item = mapTally[address]; item.nAmount += txout.nValue; // komodo_interest? item.nConf = min(item.nConf, nDepth); - item.nHeight = mapBlockIndex[wtx.hashBlock]->GetHeight(); + item.nHeight = komodo_blockheight(wtx.hashBlock); item.txids.push_back(wtx.GetHash()); if (mine & ISMINE_WATCH_ONLY) item.fIsWatchonly = true; From 564da3c9826d7d830453693a3060f2e3ddb31e1c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:33:31 -1100 Subject: [PATCH 28/43] Change mapblockindex[] into function calls with guards --- src/cc/CCutils.cpp | 2 +- src/cc/payments.cpp | 6 +++--- src/main.cpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 3c4c6c67c..f47bc4212 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -623,7 +623,7 @@ bool komodo_txnotarizedconfirmed(uint256 txid) fprintf(stderr,"komodo_txnotarizedconfirmed no hashBlock for txid %s\n",txid.ToString().c_str()); return(0); } - else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txheight= pindex->GetHeight()) <= 0 ) + else if ( (pindex= komodo_blockindex(hashBlock)) == 0 || (txheight= pindex->GetHeight()) <= 0 ) { fprintf(stderr,"komodo_txnotarizedconfirmed no txheight.%d %p for txid %s\n",txheight,pindex,txid.ToString().c_str()); return(0); diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 526fea52f..8bd41b333 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -314,10 +314,10 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & } } // check the chain depth vs locked blocks requirement. - CBlockIndex* pblockindex = mapBlockIndex[blockhash]; - if ( pblockindex->GetHeight() > ht-lockedblocks ) + CBlockIndex* pblockindex = komodo_blockindex(blockhash); + if ( pblockindex == 0 || pblockindex->GetHeight() > ht-lockedblocks ) { - fprintf(stderr, "vin.%i is not elegible to be spent yet height.%i vs elegible_ht.%i\n", i, pblockindex->GetHeight(), ht-lockedblocks); + fprintf(stderr, "vin.%i is not elegible to be spent yet height.%i vs elegible_ht.%i\n", i, pblockindex!=0?pblockindex->GetHeight():0, ht-lockedblocks); return(eval->Invalid("vin not elegible")); } } else return(eval->Invalid("cant get vin transaction")); diff --git a/src/main.cpp b/src/main.cpp index 40da1b855..2e0102b8b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6413,8 +6413,8 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) nLoaded++; if (state.IsError()) break; - } else if (hash != chainparams.GetConsensus().hashGenesisBlock && mapBlockIndex[hash]->GetHeight() % 1000 == 0) { - LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->GetHeight()); + } else if (hash != chainparams.GetConsensus().hashGenesisBlock && komodo_blockheight(hash) % 1000 == 0) { + LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), komodo_blockheight(hash)); } // Recursively process earlier encountered successors of this block From f79d72fb94630e8c4e962fc1681725c6c4615ac2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:34:31 -1100 Subject: [PATCH 29/43] Include file --- src/wallet/asyncrpcoperation_mergetoaddress.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index e5ce59a17..3268c2f0d 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -46,6 +46,7 @@ #include #include "paymentdisclosuredb.h" +#include "komodo_defs.h" using namespace libzcash; From 124156f956a3bdb8bcb79589ddb0d83b89743f00 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:36:46 -1100 Subject: [PATCH 30/43] int32_t komodo_blockheight(uint256 hash); --- src/wallet/asyncrpcoperation_mergetoaddress.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index 3268c2f0d..82860d18e 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -46,7 +46,7 @@ #include #include "paymentdisclosuredb.h" -#include "komodo_defs.h" +int32_t komodo_blockheight(uint256 hash); using namespace libzcash; From 70015ce70d6ee1dfe9cb5ab867513f7d29bf380e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:37:51 -1100 Subject: [PATCH 31/43] int32_t komodo_blockheight(uint256 hash); --- src/wallet/asyncrpcoperation_sendmany.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 45d61b885..bc335fc4c 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -55,6 +55,7 @@ using namespace libzcash; extern char ASSETCHAINS_SYMBOL[65]; int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); +int32_t komodo_blockheight(uint256 hash); int tx_height( const uint256 &hash ); extern UniValue signrawtransaction(const UniValue& params, bool fHelp); extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); From 0b66a88ba29347d1f171e255836fe70326717c84 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 21 Apr 2019 02:40:49 -1100 Subject: [PATCH 32/43] int32_t komodo_blockheight(uint256 hash); --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 028b18861..c73e177cd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -125,7 +125,7 @@ void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry) entry.push_back(Pair("confirmations", komodo_dpowconfs((int32_t)komodo_blockheight(wtx.hashBlock),confirms))); entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); entry.push_back(Pair("blockindex", wtx.nIndex)); - entry.push_back(Pair("blocktime", komodo_blocktime(wtx.hashBlock))); + entry.push_back(Pair("blocktime", (uint64_t)komodo_blocktime(wtx.hashBlock))); entry.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight)); } else entry.push_back(Pair("confirmations", confirms)); uint256 hash = wtx.GetHash(); From 74b256333469d431bf8020cca4125de26d4a2570 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Sun, 21 Apr 2019 07:58:05 -0700 Subject: [PATCH 33/43] Reduce unnecessary warnings to STDOUT --- src/komodo_bitcoind.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index b342cc932..2fc8f480e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -75,7 +75,8 @@ int tx_height( const uint256 &hash ){ nHeight = it->second->GetHeight(); //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); } else { - fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); + // Unconfirmed xtns + //fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); } return nHeight; } From 1a9f6cb60796f5ee49520c22b2ea332403505ced Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Mon, 22 Apr 2019 20:27:28 +0300 Subject: [PATCH 34/43] return OpenSSL 1.1.1a and applied patch More info: - https://github.com/openssl/openssl/issues/7350 - https://github.com/openssl/openssl/commit/f725fe5b4b6504df08e30f5194d321c3025e2336 Without this patch we will get following error: ``` SSL: couldn't create a context: error:00000000:lib(0):func(0):reason(0) ``` during trying to connect HTTPS. --- depends/packages/openssl.mk | 8 +- depends/patches/openssl/ssl_fix.patch | 273 ++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 3 deletions(-) create mode 100644 depends/patches/openssl/ssl_fix.patch diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 96908e151..5c689fe0b 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,8 +1,9 @@ package=openssl -$(package)_version=1.1.1b +$(package)_version=1.1.1a $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz -$(package)_sha256_hash=5c557b023230413dfb0756f3137a13e6d726838ccd1430888ad15bfb2b43ea4b +$(package)_sha256_hash=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41 +$(package)_patches=ssl_fix.patch define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" @@ -25,7 +26,8 @@ endef define $(package)_preprocess_cmds sed -i.old 's/built on: $date/built on: not available/' util/mkbuildinf.pl && \ - sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure + sed -i.old "s|\"engines\", \"apps\", \"test\"|\"engines\"|" Configure && \ + patch -p1 < $($(package)_patch_dir)/ssl_fix.patch endef define $(package)_config_cmds diff --git a/depends/patches/openssl/ssl_fix.patch b/depends/patches/openssl/ssl_fix.patch new file mode 100644 index 000000000..d7f79fed5 --- /dev/null +++ b/depends/patches/openssl/ssl_fix.patch @@ -0,0 +1,273 @@ +From f725fe5b4b6504df08e30f5194d321c3025e2336 Mon Sep 17 00:00:00 2001 +From: Matt Caswell +Date: Tue, 20 Nov 2018 15:32:55 +0000 +Subject: [PATCH] Fix a RUN_ONCE bug + +We have a number of instances where there are multiple "init" functions for +a single CRYPTO_ONCE variable, e.g. to load config automatically or to not +load config automatically. Unfortunately the RUN_ONCE mechanism was not +correctly giving the right return value where an alternative init function +was being used. + +Reviewed-by: Tim Hudson +(Merged from https://github.com/openssl/openssl/pull/7983) +--- + crypto/init.c | 38 +++++++++----- + include/internal/thread_once.h | 92 ++++++++++++++++++++++++++++++++++ + ssl/ssl_init.c | 6 ++- + 3 files changed, 121 insertions(+), 15 deletions(-) + +diff --git a/crypto/init.c b/crypto/init.c +index 209d1a483da..f20a12f069a 100644 +--- a/crypto/init.c ++++ b/crypto/init.c +@@ -177,12 +177,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_nodelete) + + static CRYPTO_ONCE load_crypto_strings = CRYPTO_ONCE_STATIC_INIT; + static int load_crypto_strings_inited = 0; +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_load_crypto_strings) +-{ +- /* Do nothing in this case */ +- return 1; +-} +- + DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings) + { + int ret = 1; +@@ -201,6 +195,13 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_crypto_strings) + return ret; + } + ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_load_crypto_strings, ++ ossl_init_load_crypto_strings) ++{ ++ /* Do nothing in this case */ ++ return 1; ++} ++ + static CRYPTO_ONCE add_all_ciphers = CRYPTO_ONCE_STATIC_INIT; + DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers) + { +@@ -218,6 +219,13 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_ciphers) + return 1; + } + ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_ciphers, ++ ossl_init_add_all_ciphers) ++{ ++ /* Do nothing */ ++ return 1; ++} ++ + static CRYPTO_ONCE add_all_digests = CRYPTO_ONCE_STATIC_INIT; + DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests) + { +@@ -235,7 +243,8 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_add_all_digests) + return 1; + } + +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_add_algs) ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_add_all_digests, ++ ossl_init_add_all_digests) + { + /* Do nothing */ + return 1; +@@ -255,7 +264,7 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_config) + config_inited = 1; + return 1; + } +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_config) ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_config, ossl_init_config) + { + #ifdef OPENSSL_INIT_DEBUG + fprintf(stderr, +@@ -595,8 +604,9 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_LOAD_CRYPTO_STRINGS) +- && !RUN_ONCE(&load_crypto_strings, +- ossl_init_no_load_crypto_strings)) ++ && !RUN_ONCE_ALT(&load_crypto_strings, ++ ossl_init_no_load_crypto_strings, ++ ossl_init_load_crypto_strings)) + return 0; + + if ((opts & OPENSSL_INIT_LOAD_CRYPTO_STRINGS) +@@ -604,7 +614,8 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_ADD_ALL_CIPHERS) +- && !RUN_ONCE(&add_all_ciphers, ossl_init_no_add_algs)) ++ && !RUN_ONCE_ALT(&add_all_ciphers, ossl_init_no_add_all_ciphers, ++ ossl_init_add_all_ciphers)) + return 0; + + if ((opts & OPENSSL_INIT_ADD_ALL_CIPHERS) +@@ -612,7 +623,8 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_ADD_ALL_DIGESTS) +- && !RUN_ONCE(&add_all_digests, ossl_init_no_add_algs)) ++ && !RUN_ONCE_ALT(&add_all_digests, ossl_init_no_add_all_digests, ++ ossl_init_add_all_digests)) + return 0; + + if ((opts & OPENSSL_INIT_ADD_ALL_DIGESTS) +@@ -624,7 +636,7 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_LOAD_CONFIG) +- && !RUN_ONCE(&config, ossl_init_no_config)) ++ && !RUN_ONCE_ALT(&config, ossl_init_no_config, ossl_init_config)) + return 0; + + if (opts & OPENSSL_INIT_LOAD_CONFIG) { +diff --git a/include/internal/thread_once.h b/include/internal/thread_once.h +index 224244353ab..e268a959ef3 100644 +--- a/include/internal/thread_once.h ++++ b/include/internal/thread_once.h +@@ -9,6 +9,20 @@ + + #include + ++/* ++ * DEFINE_RUN_ONCE: Define an initialiser function that should be run exactly ++ * once. It takes no arguments and returns and int result (1 for success or ++ * 0 for failure). Typical usage might be: ++ * ++ * DEFINE_RUN_ONCE(myinitfunc) ++ * { ++ * do_some_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ */ + #define DEFINE_RUN_ONCE(init) \ + static int init(void); \ + int init##_ossl_ret_ = 0; \ +@@ -17,10 +31,30 @@ + init##_ossl_ret_ = init(); \ + } \ + static int init(void) ++ ++/* ++ * DECLARE_RUN_ONCE: Declare an initialiser function that should be run exactly ++ * once that has been defined in another file via DEFINE_RUN_ONCE(). ++ */ + #define DECLARE_RUN_ONCE(init) \ + extern int init##_ossl_ret_; \ + void init##_ossl_(void); + ++/* ++ * DEFINE_RUN_ONCE_STATIC: Define an initialiser function that should be run ++ * exactly once. This function will be declared as static within the file. It ++ * takes no arguments and returns and int result (1 for success or 0 for ++ * failure). Typical usage might be: ++ * ++ * DEFINE_RUN_ONCE_STATIC(myinitfunc) ++ * { ++ * do_some_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ */ + #define DEFINE_RUN_ONCE_STATIC(init) \ + static int init(void); \ + static int init##_ossl_ret_ = 0; \ +@@ -30,6 +64,46 @@ + } \ + static int init(void) + ++/* ++ * DEFINE_RUN_ONCE_STATIC_ALT: Define an alternative initialiser function. This ++ * function will be declared as static within the file. It takes no arguments ++ * and returns an int result (1 for success or 0 for failure). An alternative ++ * initialiser function is expected to be associated with a primary initialiser ++ * function defined via DEFINE_ONCE_STATIC where both functions use the same ++ * CRYPTO_ONCE object to synchronise. Where an alternative initialiser function ++ * is used only one of the primary or the alternative initialiser function will ++ * ever be called - and that function will be called exactly once. Definitition ++ * of an alternative initialiser function MUST occur AFTER the definition of the ++ * primary initialiser function. ++ * ++ * Typical usage might be: ++ * ++ * DEFINE_RUN_ONCE_STATIC(myinitfunc) ++ * { ++ * do_some_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ * ++ * DEFINE_RUN_ONCE_STATIC_ALT(myaltinitfunc, myinitfunc) ++ * { ++ * do_some_alternative_initialisation(); ++ * if (init_is_successful()) ++ * return 1; ++ * ++ * return 0; ++ * } ++ */ ++#define DEFINE_RUN_ONCE_STATIC_ALT(initalt, init) \ ++ static int initalt(void); \ ++ static void initalt##_ossl_(void) \ ++ { \ ++ init##_ossl_ret_ = initalt(); \ ++ } \ ++ static int initalt(void) ++ + /* + * RUN_ONCE - use CRYPTO_THREAD_run_once, and check if the init succeeded + * @once: pointer to static object of type CRYPTO_ONCE +@@ -43,3 +117,21 @@ + */ + #define RUN_ONCE(once, init) \ + (CRYPTO_THREAD_run_once(once, init##_ossl_) ? init##_ossl_ret_ : 0) ++ ++/* ++ * RUN_ONCE_ALT - use CRYPTO_THREAD_run_once, to run an alternative initialiser ++ * function and check if that initialisation succeeded ++ * @once: pointer to static object of type CRYPTO_ONCE ++ * @initalt: alternative initialiser function name that was previously given to ++ * DEFINE_RUN_ONCE_STATIC_ALT. This function must return 1 for ++ * success or 0 for failure. ++ * @init: primary initialiser function name that was previously given to ++ * DEFINE_RUN_ONCE_STATIC. This function must return 1 for success or ++ * 0 for failure. ++ * ++ * The return value is 1 on success (*) or 0 in case of error. ++ * ++ * (*) by convention, since the init function must return 1 on success. ++ */ ++#define RUN_ONCE_ALT(once, initalt, init) \ ++ (CRYPTO_THREAD_run_once(once, initalt##_ossl_) ? init##_ossl_ret_ : 0) +diff --git a/ssl/ssl_init.c b/ssl/ssl_init.c +index c0ccb9304a6..96526472c57 100644 +--- a/ssl/ssl_init.c ++++ b/ssl/ssl_init.c +@@ -134,7 +134,8 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_ssl_strings) + return 1; + } + +-DEFINE_RUN_ONCE_STATIC(ossl_init_no_load_ssl_strings) ++DEFINE_RUN_ONCE_STATIC_ALT(ossl_init_no_load_ssl_strings, ++ ossl_init_load_ssl_strings) + { + /* Do nothing in this case */ + return 1; +@@ -207,7 +208,8 @@ int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS * settings) + return 0; + + if ((opts & OPENSSL_INIT_NO_LOAD_SSL_STRINGS) +- && !RUN_ONCE(&ssl_strings, ossl_init_no_load_ssl_strings)) ++ && !RUN_ONCE_ALT(&ssl_strings, ossl_init_no_load_ssl_strings, ++ ossl_init_load_ssl_strings)) + return 0; + + if ((opts & OPENSSL_INIT_LOAD_SSL_STRINGS) From 0930945aa0c7db4a990726ee24bfed7b1c8bd04b Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Mon, 22 Apr 2019 20:54:49 +0300 Subject: [PATCH 35/43] remove debug delays in libcurl.mk --- depends/packages/libcurl.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 1ce0a9161..71e9803a4 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -26,7 +26,6 @@ endif define $(package)_config_cmds echo '=== config for $(package):' && \ echo '$($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts)' && \ - sleep 10 && \ echo '=== ' && \ $($(package)_config_env) $($(package)_conf_tool) $($(package)_config_opts) endef @@ -43,6 +42,5 @@ endif define $(package)_stage_cmds echo 'Staging dir: $($(package)_staging_dir)$(host_prefix)/' && \ - sleep 10 && \ $(MAKE) DESTDIR=$($(package)_staging_dir) install endef From c4c5746e9c9988de03c506ca02354b580865e8d6 Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Mon, 22 Apr 2019 20:56:25 +0300 Subject: [PATCH 36/43] added config flags to openssl to make libcurl HTTPS connections work OpenSSL needs to be built with sock, ssl, tls and des. all other config options can be disabled, like in ZCash. --- depends/packages/openssl.mk | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index 5c689fe0b..c5ac5bb32 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -8,7 +8,71 @@ $(package)_patches=ssl_fix.patch define $(package)_set_vars $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl +$(package)_config_opts+=no-afalgeng +$(package)_config_opts+=no-asm +$(package)_config_opts+=no-async +$(package)_config_opts+=no-bf +$(package)_config_opts+=no-blake2 +$(package)_config_opts+=no-camellia +$(package)_config_opts+=no-capieng +$(package)_config_opts+=no-cast +$(package)_config_opts+=no-chacha +$(package)_config_opts+=no-cmac +$(package)_config_opts+=no-cms +$(package)_config_opts+=no-comp +$(package)_config_opts+=no-crypto-mdebug +$(package)_config_opts+=no-crypto-mdebug-backtrace +$(package)_config_opts+=no-ct +$(package)_config_opts+=no-dgram +$(package)_config_opts+=no-dsa +$(package)_config_opts+=no-dso +$(package)_config_opts+=no-dtls +$(package)_config_opts+=no-dtls1 +$(package)_config_opts+=no-dtls1-method +$(package)_config_opts+=no-dynamic-engine +$(package)_config_opts+=no-ec2m +$(package)_config_opts+=no-ec_nistp_64_gcc_128 +$(package)_config_opts+=no-egd +$(package)_config_opts+=no-engine +$(package)_config_opts+=no-err +$(package)_config_opts+=no-gost +$(package)_config_opts+=no-heartbeats +$(package)_config_opts+=no-idea +$(package)_config_opts+=no-md2 +$(package)_config_opts+=no-md4 +$(package)_config_opts+=no-mdc2 +$(package)_config_opts+=no-multiblock +$(package)_config_opts+=no-nextprotoneg +$(package)_config_opts+=no-ocb +$(package)_config_opts+=no-ocsp +$(package)_config_opts+=no-poly1305 +$(package)_config_opts+=no-posix-io +$(package)_config_opts+=no-psk +$(package)_config_opts+=no-rc2 +$(package)_config_opts+=no-rc4 +$(package)_config_opts+=no-rc5 +$(package)_config_opts+=no-rdrand +$(package)_config_opts+=no-rfc3779 +$(package)_config_opts+=no-rmd160 +$(package)_config_opts+=no-scrypt +$(package)_config_opts+=no-sctp +$(package)_config_opts+=no-seed $(package)_config_opts+=no-shared +$(package)_config_opts+=no-srp +$(package)_config_opts+=no-srtp +$(package)_config_opts+=no-ssl3 +$(package)_config_opts+=no-ssl3-method +$(package)_config_opts+=no-ssl-trace +$(package)_config_opts+=no-stdio +$(package)_config_opts+=no-tls1 +$(package)_config_opts+=no-tls1-method +$(package)_config_opts+=no-ts +$(package)_config_opts+=no-ui +$(package)_config_opts+=no-unit-test +$(package)_config_opts+=no-weak-ssl-ciphers +$(package)_config_opts+=no-whirlpool +$(package)_config_opts+=no-zlib +$(package)_config_opts+=no-zlib-dynamic $(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) $(package)_config_opts+=-DPURIFY $(package)_config_opts_linux=-fPIC -Wa,--noexecstack From a0053d8ef082d085f1d5ecf817167a809cf82953 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Wed, 24 Apr 2019 13:02:08 +0200 Subject: [PATCH 37/43] Defragmenting utxos in Gateways deposit address (#24) - adding up to 3 more utxos when doing withdraw for defragmentation - corrected gateways validation --- src/cc/dapps/oraclefeed.c | 45 ++++++++++++++++++++++----------------- src/cc/gateways.cpp | 35 ++++++++++++++++-------------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index 6ac014ad1..4687837ac 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -592,7 +592,7 @@ void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys) cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) { - cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid; + cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,j=0,n,v; int64_t satoshis; bits256 txid; *totalp = 0; if ( (n= cJSON_GetArraySize(unspents)) > 0 ) { @@ -610,7 +610,10 @@ cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) jaddi(vins,vin); *totalp += satoshis; if ( (*totalp) >= required ) - break; + { + if (j<3) j++; + else break; + } } } } @@ -910,10 +913,11 @@ void update_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxi processed++; } free(rawtx); - } else fprintf(stderr,"couldnt create rawtx\n"); + } else fprintf(stderr,"couldnt create rawtx\n"); } else { + rawtx=0; lasttxid = jbits256(item,"last_txid"); if ( lasttxid.txid==withdrawtxid.txid) { @@ -921,24 +925,27 @@ void update_gatewayspending(int8_t type,char *refcoin,char *acname,char *bindtxi } else rawtx=jstr(item,"hex"); K=jint(item,"number_of_signs"); - if ( rawtx!=0 && (clijson=addsignature(refcoin,"",rawtx,M)) != 0 ) + if (rawtx!=0) { - if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) - { - txid=gatewayscompletesigning(type,refcoin,acname,lasttxid,jstr(clijson,"hex")); - if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %dof%d\n",bits256_str(str,withdrawtxid),K+1,N); - else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname); - } - else if ( jint(clijson,"partialtx") != 0 ) + if ((clijson=addsignature(refcoin,"",rawtx,M)) != 0 ) { - txid=gatewayspartialsign(type,refcoin,acname,lasttxid,jstr(clijson,"hex")); - if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %d/%dof%d\n",bits256_str(str,withdrawtxid),K+1,M,N); - else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname); - } - free_json(clijson); - processed++; - if ( lasttxid.txid==withdrawtxid.txid) free(rawtx); - } + if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) + { + txid=gatewayscompletesigning(type,refcoin,acname,lasttxid,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %dof%d\n",bits256_str(str,withdrawtxid),K+1,N); + else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname); + } + else if ( jint(clijson,"partialtx") != 0 ) + { + txid=gatewayspartialsign(type,refcoin,acname,lasttxid,jstr(clijson,"hex")); + if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %d/%dof%d\n",bits256_str(str,withdrawtxid),K+1,M,N); + else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname); + } + free_json(clijson); + processed++; + if ( lasttxid.txid==withdrawtxid.txid) free(rawtx); + } + } else fprintf(stderr,"couldnt create rawtx or find previous partial signed tx\n"); } } } diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index d88b3d25f..00c80082b 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -628,20 +628,25 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("deposit amount greater then bind total supply"); else if (komodo_txnotarizedconfirmed(deposittxid) == false) return eval->Invalid("gatewaysdeposit tx is not yet confirmed(notarised)!"); - else if (myGetTransaction(tx.vin[2].prevout.hash,tmptx,hashblock) == 0) - return eval->Invalid("invalid gatewaysdeposittxid!"); else if (IsCCInput(tx.vin[0].scriptSig) != 0) return eval->Invalid("vin.0 is normal for gatewaysclaim!"); - else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || myGetTransaction(tx.vin[tx.vin.size()-1].prevout.hash,tmptx,hashblock)==0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + else if (tx.vin.size()>2) + { + i=1; + while (i<=tx.vin.size()-2) + { + if (IsCCInput(tx.vin[i].scriptSig)==0) return eval->Invalid("vin."+std::to_string(i)+" is CC for gatewaysclaim!"); + i++; + } + } + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || tmptx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker for gatewaysclaim or invalid marker amount!"); else if (_GetCCaddress(destaddr,EVAL_TOKENS,pubkey)==0 || ConstrainVout(tx.vout[0],1,destaddr,amount)==0) return eval->Invalid("invalid vout tokens to destpub for gatewaysclaim!"); - else if (numvouts>2 && (myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || ConstrainVout(tx.vout[1],1,gatewaystokensaddr,tmptx.vout[tx.vin[1].prevout.n].nValue-amount)==0)) + else if (numvouts>2 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() && (myGetTransaction(tx.vin[1].prevout.hash,tmptx,hashblock)==0 || ConstrainVout(tx.vout[1],1,gatewaystokensaddr,tmptx.vout[tx.vin[1].prevout.n].nValue-amount)==0)) return eval->Invalid("invalid CC change vout for gatewaysclaim!"); else if (amount!=tmpamount) - return eval->Invalid("claimed amount different then deposit amount"); - else if (tx.vout[0].nValue!=amount) - return eval->Invalid("claim amount not matching amount in opret"); + return eval->Invalid("claimed amount different then deposit amount"); else if (pubkey!=tmppubkey) return eval->Invalid("claim destination pubkey different than in deposit tx"); else @@ -697,8 +702,6 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("invalid marker vout for gatewaysWithdraw!"); else if ( ConstrainVout(tmptx.vout[1],1,gatewaystokensaddr,amount)==0) return eval->Invalid("invalid tokens to gateways vout for gatewaysWithdraw!"); - else if (tmptx.vout[1].nValue!=amount) - return eval->Invalid("amount in opret not matching tx tokens amount!"); else if (komodo_txnotarizedconfirmed(withdrawtxid) == false) return eval->Invalid("gatewayswithdraw tx is not yet confirmed(notarised)!"); else if (myGetTransaction(bindtxid,tmptx,hashblock) == 0) @@ -953,7 +956,7 @@ std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,2) > 0 ) { if (AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, totalsupply, 64)>0) { @@ -1032,7 +1035,7 @@ std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std:: LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if ( AddNormalinputs(mtx,mypk,txfee+2*CC_MARKER_VALUE,4) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee+2*CC_MARKER_VALUE,3) > 0 ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,CC_MARKER_VALUE,destpub)); mtx.vout.push_back(CTxOut(CC_MARKER_VALUE,CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr,cointxid))) << OP_CHECKSIG)); @@ -1104,7 +1107,7 @@ std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,ui LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if ( AddNormalinputs(mtx,mypk,txfee,3) > 0 ) + if ( AddNormalinputs(mtx,mypk,txfee,1) > 0 ) { if ((inputs=AddGatewaysInputs(cp, mtx, gatewayspk, bindtxid, amount, 60)) > 0) { @@ -1182,7 +1185,7 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin } } } - if( AddNormalinputs(mtx, mypk, txfee+CC_MARKER_VALUE, 4) > 0 ) + if( AddNormalinputs(mtx, mypk, txfee+CC_MARKER_VALUE, 2) > 0 ) { if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, amount, 60)) > 0) { @@ -1294,7 +1297,7 @@ std::string GatewaysPartialSign(uint64_t txfee,uint256 lasttxid,std::string refc return(""); } } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + if (AddNormalinputs(mtx,mypk,txfee,1)!=0) { mtx.vin.push_back(CTxIn(tx.GetHash(),0,CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CC_MARKER_VALUE,gatewayspk)); @@ -1393,7 +1396,7 @@ std::string GatewaysCompleteSigning(uint64_t txfee,uint256 lasttxid,std::string return(""); } } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + if (AddNormalinputs(mtx,mypk,txfee,1)!=0) { mtx.vin.push_back(CTxIn(lasttxid,0,CScript())); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CC_MARKER_VALUE,gatewayspk)); @@ -1458,7 +1461,7 @@ std::string GatewaysMarkDone(uint64_t txfee,uint256 completetxid,std::string ref LOGSTREAM("gatewayscc",CCLOG_INFO, stream << CCerror << std::endl); return(""); } - if (AddNormalinputs(mtx,mypk,txfee,3)!=0) + if (AddNormalinputs(mtx,mypk,txfee,1)!=0) { mtx.vin.push_back(CTxIn(completetxid,0,CScript())); mtx.vout.push_back(CTxOut(CC_MARKER_VALUE,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); From 8a574b96237a25218d7926e28461c43ff1f53e1b Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Wed, 24 Apr 2019 17:30:21 +0200 Subject: [PATCH 38/43] Corrected ChannelsCC validation. --- src/cc/channels.cpp | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 254f7e3a5..64bb95572 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -250,10 +250,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("channelopen is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelpayment!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for channelpayment!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for channelpayment!"); + else if ( IsCCInput(tx.vin[tx.vin.size()-2].scriptSig) == 0 ) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-2)+" is CC for channelpayment!"); else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 ) return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelpayment!"); else if ( ConstrainVout(tx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 ) @@ -283,8 +281,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("invalid previous tx OP_RETURN data!"); else if ( ConstrainVout(tx.vout[0],1,channeladdress,(p1-param2)*payment)==0 ) return eval->Invalid("vout.0 is CC or invalid CC change amount for channelpayment!"); - else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelpayment!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || prevTx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker or invalid marker amount for channelpayment!"); else if (param1+param2!=p1) return eval->Invalid("invalid payment depth!"); else if (tx.vout[3].nValue > prevTx.vout[0].nValue) @@ -313,10 +311,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("channelopen is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelclose!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for channelclose!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for channelclose!"); + else if ( IsCCInput(tx.vin[tx.vin.size()-2].scriptSig) == 0 ) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-2)+" is CC for channelclose!"); else if ( ConstrainVout(tx.vout[0],1,channeladdress,0)==0 ) return eval->Invalid("vout.0 is CC for channelclose!"); else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 ) @@ -329,8 +325,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { 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 ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelclose!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || prevTx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker or invalid marker amount for channelclose!"); else if (tx.vout[0].nValue != prevTx.vout[0].nValue) return eval->Invalid("invalid CC amount, amount must match funds in channel"); } @@ -358,10 +354,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("channelClose is not yet confirmed(notarised)!"); else if ( IsCCInput(tx.vin[0].scriptSig) != 0 ) return eval->Invalid("vin.0 is normal for channelrefund!"); - else if ( IsCCInput(tx.vin[1].scriptSig) == 0 ) - return eval->Invalid("vin.1 is CC for channelrefund!"); - else if ( IsCCInput(tx.vin[2].scriptSig) == 0 ) - return eval->Invalid("vin.2 is CC for channelrefund!"); + else if ( IsCCInput(tx.vin[tx.vin.size()-2].scriptSig) == 0 ) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-2)+" CC for channelrefund!"); else if ( ConstrainVout(tx.vout[0],1,srcmarker,CC_MARKER_VALUE)==0 ) return eval->Invalid("vout.0 is CC marker to srcpub or invalid amount for channelrefund!"); else if ( ConstrainVout(tx.vout[1],1,destmarker,CC_MARKER_VALUE)==0 ) @@ -376,8 +370,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { 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 ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE) - return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelrefund!"); + else if ((*cp->ismyvin)(tx.vin[tx.vin.size()-1].scriptSig) == 0 || prevTx.vout[tx.vin[tx.vin.size()-1].prevout.n].nValue!=CC_MARKER_VALUE) + return eval->Invalid("vin."+std::to_string(tx.vin.size()-1)+" is CC marker or invalid marker amount for channelrefund!"); else if (tx.vout[2].nValue != prevTx.vout[0].nValue) return eval->Invalid("invalid amount, refund amount and funds in channel must match!"); } From 6af417b9901a84cdb844b2baf512e78285a7d6af Mon Sep 17 00:00:00 2001 From: DeckerSU Date: Thu, 25 Apr 2019 14:24:53 +0300 Subject: [PATCH 39/43] build-mac.sh fix on latest libcurl changes https://github.com/jl777/komodo/issues/1452 --- depends/packages/libcurl.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 71e9803a4..159817139 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -32,7 +32,7 @@ endef ifeq ($(build_os),darwin) define $(package)_build_cmds - $(MAKE) CPPFLAGS='-fPIC' CFLAGS='-mmacosx-version-min=10.9' + $(MAKE) CPPFLAGS="-I$(host_prefix)/include -fPIC" CFLAGS='-mmacosx-version-min=10.9' endef else define $(package)_build_cmds From a19e28371513589fdc4b1f6195a775922af73d34 Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sat, 27 Apr 2019 17:48:06 +0800 Subject: [PATCH 40/43] add dpow to BEER, fix crashed node not being able to sync due to future checkpoints. --- src/komodo.h | 2 +- src/main.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 15c1e5c02..b4c7d12bf 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -621,7 +621,7 @@ int32_t komodo_voutupdate(bool fJustCheck,int32_t *isratificationp,int32_t notar memset(&MoMoMdata,0,sizeof(MoMoMdata)); if ( matched == 0 && signedmask != 0 && bitweight(signedmask) >= KOMODO_MINRATIFY ) notarized = 1; - if ( strcmp("PIZZA",ccdata.symbol) == 0 || strncmp("TXSCL",ccdata.symbol,5) == 0 ) + if ( strcmp("PIZZA",ccdata.symbol) == 0 || strncmp("TXSCL",ccdata.symbol,5) == 0 || strcmp("BEER",ccdata.symbol) == 0) notarized = 1; if ( 0 && opretlen != 149 ) printf("[%s].%d (%s) matched.%d i.%d j.%d notarized.%d %llx opretlen.%d len.%d offset.%d opoffset.%d\n",ASSETCHAINS_SYMBOL,height,ccdata.symbol,matched,i,j,notarized,(long long)signedmask,opretlen,len,offset,opoffset); diff --git a/src/main.cpp b/src/main.cpp index e0e40c9a5..352bd65fb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4243,7 +4243,7 @@ static bool ActivateBestChainStep(bool fSkipdpow, CValidationState &state, CBloc // stay on the same chain tip! int32_t notarizedht,prevMoMheight; uint256 notarizedhash,txid; notarizedht = komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); - if ( !fSkipdpow && pindexFork != 0 && pindexFork->GetHeight() < notarizedht ) + if ( !fSkipdpow && pindexFork != 0 && pindexOldTip->GetHeight() > notarizedht && pindexFork->GetHeight() < notarizedht ) { fprintf(stderr,"pindexFork->GetHeight().%d is < notarizedht %d, so ignore it\n",(int32_t)pindexFork->GetHeight(),notarizedht); return state.DoS(100, error("ActivateBestChainStep(): pindexFork->GetHeight().%d is < notarizedht %d, so ignore it",(int32_t)pindexFork->GetHeight(),notarizedht), From 3110814bae5b91a30a5518f467c371d61501ca56 Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Sat, 27 Apr 2019 20:36:33 +0800 Subject: [PATCH 41/43] add extr print for new fix --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 352bd65fb..45d2e7a39 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4245,8 +4245,8 @@ static bool ActivateBestChainStep(bool fSkipdpow, CValidationState &state, CBloc notarizedht = komodo_notarized_height(&prevMoMheight,¬arizedhash,&txid); if ( !fSkipdpow && pindexFork != 0 && pindexOldTip->GetHeight() > notarizedht && pindexFork->GetHeight() < notarizedht ) { - fprintf(stderr,"pindexFork->GetHeight().%d is < notarizedht %d, so ignore it\n",(int32_t)pindexFork->GetHeight(),notarizedht); - return state.DoS(100, error("ActivateBestChainStep(): pindexFork->GetHeight().%d is < notarizedht %d, so ignore it",(int32_t)pindexFork->GetHeight(),notarizedht), + fprintf(stderr,"pindexOldTip->GetHeight().%d > notarizedht %d && pindexFork->GetHeight().%d is < notarizedht %d, so ignore it\n",(int32_t)pindexFork->GetHeight(),notarizedht,(int32_t)pindexOldTip->GetHeight(),notarizedht); + return state.DoS(100, error("ActivateBestChainStep(): pindexOldTip->GetHeight().%d > notarizedht %d && pindexFork->GetHeight().%d is < notarizedht %d, so ignore it",(int32_t)pindexFork->GetHeight(),notarizedht,(int32_t)pindexOldTip->GetHeight(),notarizedht), REJECT_INVALID, "past-notarized-height"); } // - On ChainDB initialization, pindexOldTip will be null, so there are no removable blocks. From cf6f647d1eb1d20a10e0f3303448c61b2d2c51ec Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Mon, 29 Apr 2019 11:25:23 +0800 Subject: [PATCH 42/43] fix wallet corruption fix, for staking chains, fix forced rescan for ZEX and KMD with ztx in wallet. --- src/wallet/walletdb.cpp | 53 +++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 5631fb79e..efba38d9e 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -485,11 +485,16 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssValue >> wtx; CValidationState state; auto verifier = libzcash::ProofVerifier::Strict(); - if (!(CheckTransaction(0,wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid())) + // ac_public chains set at height like KMD and ZEX, will force a rescan if we dont ignore this error: bad-txns-acpublic-chain + // there cannot be any ztx in the wallet on ac_public chains that started from block 1, so this wont affect those. + if ( !(CheckTransaction(0,wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()) && (state.GetRejectReason() != "bad-txns-acpublic-chain") ) { - deadTxns.push_back(hash); + //fprintf(stderr, "tx failed: %s rejectreason.%s\n", wtx.GetHash().GetHex().c_str(), state.GetRejectReason().c_str()); + // vin-empty on staking chains is error relating to a failed staking tx, that for some unknown reason did not fully erase. save them here to erase and re-add later on. + if ( ASSETCHAINS_STAKED != 0 && state.GetRejectReason() == "bad-txns-vin-empty" ) + deadTxns.push_back(hash); return false; - } + } // Undo serialize changes in 31600 if (31404 <= wtx.fTimeReceivedIsTxTime && wtx.fTimeReceivedIsTxTime <= 31703) { @@ -937,6 +942,9 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) { // Leave other errors alone, if we try to fix them we might make things worse. fNoncriticalErrors = true; // ... but do warn the user there is something wrong. + // set rescan for any error that is not vin-empty on staking chains. + if ( deadTxns.empty() && strType == "tx") + SoftSetBoolArg("-rescan", true); } } if (!strErr.empty()) @@ -953,33 +961,26 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet) if ( !deadTxns.empty() ) { - if ( ASSETCHAINS_STAKED != 0 ) + // staking chains with vin-empty error is a failed staking tx. + // we remove then re add the tx here to stop needing a full rescan, which does not actually fix the problem. + int32_t reAdded = 0; + CWalletDB walletdb(pwallet->strWalletFile, "r+", false); + BOOST_FOREACH (uint256& hash, deadTxns) { - int32_t reAdded = 0; - CWalletDB walletdb(pwallet->strWalletFile, "r+", false); - BOOST_FOREACH (uint256& hash, deadTxns) + fprintf(stderr, "Removing corrupt tx from wallet.%s\n", hash.ToString().c_str()); + if (!EraseTx(hash)) + fprintf(stderr, "could not delete tx.%s\n",hash.ToString().c_str()); + uint256 blockhash; CTransaction tx; + if (GetTransaction(hash,tx,blockhash,true)) { - fprintf(stderr, "Removing corrupt tx from wallet.%s\n", hash.ToString().c_str()); - if (!EraseTx(hash)) - fprintf(stderr, "could not delete tx.%s\n",hash.ToString().c_str()); - uint256 blockhash; CTransaction tx; - if (GetTransaction(hash,tx,blockhash,true)) - { - CWalletTx wtx(pwallet,tx); - pwallet->AddToWallet(wtx, false, &walletdb); - reAdded++; - } + CWalletTx wtx(pwallet,tx); + pwallet->AddToWallet(wtx, false, &walletdb); + reAdded++; } - fprintf(stderr, "Cleared %lu corrupted transactions from wallet. Readded %i known transactions.\n",(long)deadTxns.size(),reAdded); - fNoncriticalErrors = false; - deadTxns.clear(); - } - else if ( (GetBoolArg("-zapwallettxes", false)) ) - { - LogPrintf("Transactions are corrupted. Please restart daemon with -zapwallettxes=2\n"); - fprintf(stderr,"Transactions are corrupted. Please restart daemon with -zapwallettxes=2\n"); - return DB_CORRUPT; } + fprintf(stderr, "Cleared %li corrupted transactions from wallet. Readded %i known transactions.\n",deadTxns.size(),reAdded); + fNoncriticalErrors = false; + deadTxns.clear(); } if (fNoncriticalErrors && result == DB_LOAD_OK) From a0aaff137153810c39833d7ce8eb44a14511bf7b Mon Sep 17 00:00:00 2001 From: dimxy Date: Mon, 29 Apr 2019 12:32:41 +0500 Subject: [PATCH 43/43] fix unmarshal source symbol from rawproof --- src/rpc/rawtransaction.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index c5d2bea86..1c3cb96f2 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -217,7 +217,8 @@ void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& { if (rawproof.size() > 0) { - std::string sourceSymbol(rawproof.begin(), rawproof.end()); + std::string sourceSymbol; + E_UNMARSHAL(rawproof, ss >> sourceSymbol); in.push_back(Pair("address", "IMP-" + sourceSymbol + "-" + burnTx.GetHash().ToString())); } }