From a994a2c01504d44b7bcdf296ae87e71c58d83b7f Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 16 Feb 2019 21:39:01 +0500 Subject: [PATCH 01/17] corrected invalid non-canonical corrected burntx nExpiryHeight to prevent duplication of importtx (malleability) added importcoin validation for amount, ac_pubkey added sourcetx creation with amount in opret --- src/cc/import.cpp | 369 ++++++++++++++++++++++++++++++++++----- src/importcoin.cpp | 7 +- src/importcoin.h | 2 +- src/rpc/crosschain.cpp | 144 ++++++++++++--- src/rpc/server.cpp | 3 +- src/rpc/server.h | 2 +- src/wallet/rpcwallet.cpp | 52 ++++++ 7 files changed, 505 insertions(+), 74 deletions(-) diff --git a/src/cc/import.cpp b/src/cc/import.cpp index ea69745b0..dbbf7832f 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -20,6 +20,10 @@ #include "primitives/transaction.h" #include "cc/CCinclude.h" +//#define LEV_INFO 0 +//#define LEV_DEBUG1 1 +//#define LOGSTREAM(category, level, logoperator) { std::ostringstream stream; logoperator; for(int i = 0; i < level; i ++) if( LogAcceptCategory( (std::string(category) + (level > 0 ? std::string("-")+std::to_string(level) : std::string("") )).c_str() ) ) LogPrintStr(stream.str()); } + /* * CC Eval method for import coin. * @@ -33,63 +37,299 @@ extern std::string ASSETCHAINS_SELFIMPORT; extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT; extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; -int32_t GetSelfimportProof(std::string source,CMutableTransaction &mtx,CScript &scriptPubKey,TxProof &proof,uint64_t burnAmount,std::vector rawtx,uint256 txid,std::vector rawproof) // find burnTx with hash from "other" daemon +// utilities from gateways.cpp +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, std::string &coin, uint256 &tokenid, int64_t &totalsupply, uint256 &oracletxid, uint8_t &M, uint8_t &N, std::vector &pubkeys, uint8_t &taddr, uint8_t &prefix, uint8_t &prefix2); + +// ac_import=chain support: +// encode opret for gateways import +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) { - MerkleBranch newBranch; CMutableTransaction tmpmtx; CTransaction tx,vintx; uint256 blockHash; char destaddr[64],pkaddr[64]; - tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_nextheight()); - if ( source == "BEAM" ) + CScript opret; + opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount); + return(opret); +} + +bool ImportCoinGatewaysVerify(char *refdepositaddr, uint256 oracletxid, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vectorproof, uint256 merkleroot) +{ + std::vector txids; + uint256 proofroot, hashBlock, foundtxid = zeroid; + CTransaction oracletx, burntx; + std::string name, description, format; + char destaddr[64], destpubaddr[64], claimaddr[64]; + int32_t i, numvouts; + int64_t nValue = 0; + + if (myGetTransaction(oracletxid, oracletx, hashBlock) == 0 || (numvouts = oracletx.vout.size()) <= 0) { - if ( ASSETCHAINS_BEAMPORT == 0 ) - return(-1); - // confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn - // return(0); + LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify can't find oracletxid=" << oracletxid.GetHex() << std::endl); + return false; } - else if ( source == "CODA" ) + if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin) { - if ( ASSETCHAINS_CODAPORT == 0 ) - return(-1); - // confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn - // return(0); + LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl); + return false; } - else + proofroot = BitcoinGetProofMerkleRoot(proof, txids); + if (proofroot != merkleroot) { - if ( !E_UNMARSHAL(rawtx, ss >> tx) ) - return(-1); - scriptPubKey = tx.vout[0].scriptPubKey; - mtx = tx; - mtx.fOverwintered = tmpmtx.fOverwintered; - mtx.nExpiryHeight = tmpmtx.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; - if ( tx.GetHash() != txid ) - return(-1); - if ( source == "PUBKEY" ) + LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl); + return false; + } + + // check the burntxid is in the proof: + if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify invalid proof for this burntxid=" << burntxid.GetHex() << std::endl); + return false; + } + + /* + if (DecodeHexTx(burntx, rawburntx) != 0) + { + Getscriptaddress(claimaddr, burntx.vout[claimvout].scriptPubKey); + Getscriptaddress(destpubaddr, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG); + if (strcmp(claimaddr, destpubaddr) == 0) { - // make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33 - if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,blockHash) == 0 ) - return(-1); - if ( tx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr,vintx.vout[tx.vin[0].prevout.n].scriptPubKey) != 0 ) + for (i = 0; i %s vs %s\n",tx.vin[0].prevout.n,destaddr,pkaddr); } } - else if ( source == ASSETCHAINS_SELFIMPORT ) + else fprintf(stderr, "claimaddr.(%s) != destpubaddr.(%s)\n", claimaddr, destpubaddr); + }*/ + + /* + if (foundtxid == burntxid) { + LOGSTREAM("importcoin", LEV_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in merkleroot merkleroot" << std::endl); + return(nValue); + } + else { + LOGSTREAM("importcoin", LEV_INFO, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in merkleroot merkleroot" << std::endl); + + fprintf(stderr, "(%s) != (%s) or txid %s mismatch.%d or script mismatch\n", refdepositaddr, destaddr, uint256_str(str, foundtxid), foundtxid != burntxid); + */ + + 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 bindtxid, int32_t height, std::string refcoin, std::vectorproof, std::string rawburntx, int32_t ivout, uint256 burntxid) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CTransaction burntx, bindtx; + CPubKey mypk, gatewayspk; + uint256 oracletxid, merkleroot, mhash, hashBlock, tokenid, txid; + int64_t totalsupply; + int32_t i, m, n, numvouts; + uint8_t M, N, taddr, prefix, prefix2; + std::string coin; + struct CCcontract_info *cp, C; + std::vector pubkeys, publishers; + std::vectortxids; + char depositaddr[64], txidaddr[64]; + + cp = CCinit(&C, EVAL_GATEWAYS); + /*if (txfee == 0) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + gatewayspk = GetUnspendable(cp, 0); */ + + 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(bindtxid, bindtx, hashBlock, false) == 0 || (numvouts = bindtx.vout.size()) <= 0) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find bindtxid=" << bindtxid.GetHex() << std::endl); + return(""); + } +/* if (DecodeGatewaysBindOpRet(depositaddr, bindtx.vout[numvouts - 1].scriptPubKey, coin, tokenid, totalsupply, oracletxid, M, N, pubkeys, taddr, prefix, prefix2) != 'B' || refcoin != coin) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid coin - bindtxid=" << bindtxid.GetHex() << " coin=" << coin.c_str() << std::endl); + return(""); + } eliminate link err */ + n = (int32_t)pubkeys.size(); + merkleroot = zeroid; + for (i = m = 0; i < n; i++) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl); + if ((mhash = GatewaysReverseScan(txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid) { - // source is external coin is the assetchains symbol in the burnTx OP_RETURN - // burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent + if (merkleroot == zeroid) + merkleroot = mhash, m = 1; + else if (mhash == merkleroot) + m ++; + publishers.push_back(pubkeys[i]); + txids.push_back(txid); } } - return(-1); + + 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=" << coin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl ); + return(""); + } + if (GatewaysCointxidExists(cp, burntxid) != 0) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " already exists" << std::endl); + return(""); + } + if (!ImportCoinGatewaysVerify(depositaddr, oracletxid, ivout, coin, burntxid, rawburntx, proof, merkleroot)) + { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx could not validate burntx, txid=" << burntxid.GetHex() << std::endl); + return(""); + } + + + std::vector leaftxids; + BitcoinGetProofMerkleRoot(proof, leaftxids); + MerkleBranch newBranch(0, leaftxids); + TxProof txProof = std::make_pair(burntxid, newBranch); + + std::vector vouts; + + + + return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts))); + + /*if (AddNormalinputs(mtx, mypk, 3 * txfee, 4) > 0) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, destpub)); + mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr, burntxid))) << OP_CHECKSIG)); + return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeGatewaysImportTxOpRet(0xFFFFFFFF, coin, bindtxid, publishers, txids, height, burntxid, ivout, rawburntx, proof, destpub, amount))); + } + LOGSTREAM("importcoin", LEV_INFO, stream << "MakeGatewaysImportTx coud not find normal imputs" << std::endl);*/ + return(""); +} + +// makes source tx for self import tx +std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx) +{ + const int64_t txfee = 10000; + int64_t inputs, change; + CPubKey myPubKey = Mypubkey(); + struct CCcontract_info *cpDummy, C; + + cpDummy = CCinit(&C, EVAL_TOKENS); + + 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(""); + } + + 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 sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33 +int32_t CheckVin0PubKey(const CTransaction &sourcetx) +{ + 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( sourcetx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[0].prevout.n].scriptPubKey) != 0 ) + { + pubkey2addr(pkaddr, ASSETCHAINS_OVERRIDE_PUBKEY33); + if (strcmp(pkaddr, destaddr) == 0) { + return(0); + } + LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() mismatched vin0[prevout.n=" << sourcetx.vin[0].prevout.n << "] -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl); + } + return -1; +} + +// 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 +{ + MerkleBranch newBranch; + CMutableTransaction tmpmtx; + 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); + } + + 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" + // try to find vout + CPubKey myPubkey = Mypubkey(); + ivout = 0; + // skip change: + if (sourcetx.vout[ivout].scriptPubKey == (CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG)) + ivout++; + } + + 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); + + scriptPubKey = sourcetx.vout[ivout].scriptPubKey; + + //mtx is template for import tx + mtx = sourcetx; + mtx.fOverwintered = tmpmtx.fOverwintered; + + //malleability fix for burn tx: + //mtx.nExpiryHeight = tmpmtx.nExpiryHeight; + mtx.nExpiryHeight = sourcetx.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; + + // 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) { + return -1; + } + proof = std::make_pair(sourcetxid, newBranch); + return 0; } // use proof from the above functions to validate the import @@ -116,9 +356,46 @@ int32_t CheckGATEWAYimport(TxProof proof,std::vector rawproof,CTransact int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransaction burnTx,std::vector payouts) { // if burnTx has ASSETCHAINS_PUBKEY vin, it is valid return(0); - fprintf(stderr,"proof txid.%s\n",proof.first.GetHex().c_str()); + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "proof txid=" << proof.first.GetHex() << std::endl); + + uint256 sourcetxid = proof.first, hashBlock; + CTransaction sourcetx; + + if (!myGetTransaction(sourcetxid, sourcetx, hashBlock)) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "could not load source txid=" << sourcetxid.GetHex() << std::endl); + return -1; + } + + if (sourcetx.vout.size() == 0) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "no vouts in source txid=" << sourcetxid.GetHex() << std::endl); + return -1; + } + + //ac_pubkey check: + if (CheckVin0PubKey(sourcetx) < 0) { + return -1; + } + + // get source tx opret: + std::vector vopret; + 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); + return -1; + } + + LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "importTx amount=" << payouts[0].nValue << " burnTx amount=" << burnTx.vout[0].nValue << " opret amount=" << amount << " source txid=" << sourcetxid.GetHex() << std::endl); + + // amount malleability check with the opret from the source tx: + if (payouts[0].nValue != amount) { // assume that burntx amount is checked in the common code in Eval::ImportCoin() + LOGSTREAM("importcoin", CCLOG_INFO, stream << "importTx amount != amount in the opret of source txid=" << sourcetxid.GetHex() << std::endl); + return -1; + } + return(0); - return(-1); } bool Eval::ImportCoin(const std::vector params,const CTransaction &importTx,unsigned int nIn) @@ -132,10 +409,10 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo return Invalid("invalid-params"); // Control all aspects of this transaction // It should not be at all malleable - if (MakeImportCoinTransaction(proof, burnTx, payouts).GetHash() != importTx.GetHash()) + if (MakeImportCoinTransaction(proof, burnTx, payouts, importTx.nExpiryHeight).GetHash() != importTx.GetHash()) return Invalid("non-canonical"); // burn params - if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash,rawproof)) + if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof)) return Invalid("invalid-burn-tx"); // check burn amount { diff --git a/src/importcoin.cpp b/src/importcoin.cpp index 39ff01d68..381a52fb8 100644 --- a/src/importcoin.cpp +++ b/src/importcoin.cpp @@ -26,14 +26,17 @@ int32_t komodo_nextheight(); -CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector payouts) +CTransaction MakeImportCoinTransaction(const TxProof proof, const CTransaction burnTx, const std::vector payouts, uint32_t nExpiryHeightOverride) { std::vector payload = E_MARSHAL(ss << EVAL_IMPORTCOIN); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); mtx.vin.push_back(CTxIn(COutPoint(burnTx.GetHash(), 10e8), CScript() << payload)); mtx.vout = payouts; auto importData = E_MARSHAL(ss << proof; ss << burnTx); mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << importData)); + + if (nExpiryHeightOverride != 0) + mtx.nExpiryHeight = nExpiryHeightOverride; //this is for construction of the tx used for validating importtx return CTransaction(mtx); } diff --git a/src/importcoin.h b/src/importcoin.h index 64019ac8f..947debcd8 100644 --- a/src/importcoin.h +++ b/src/importcoin.h @@ -26,7 +26,7 @@ CAmount GetCoinImportValue(const CTransaction &tx); CTransaction MakeImportCoinTransaction(const TxProof proof, - const CTransaction burnTx, const std::vector payouts); + 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); diff --git a/src/rpc/crosschain.cpp b/src/rpc/crosschain.cpp index a0a3b507f..1a6dc41ea 100644 --- a/src/rpc/crosschain.cpp +++ b/src/rpc/crosschain.cpp @@ -34,21 +34,27 @@ #include "script/sign.h" #include "script/standard.h" +#include "key_io.h" + #include #include #include - using namespace std; +extern std::string ASSETCHAINS_SELFIMPORT; +extern uint16_t ASSETCHAINS_CODAPORT, ASSETCHAINS_BEAMPORT; + 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); struct komodo_ccdata_entry *komodo_allMoMs(int32_t *nump,uint256 *MoMoMp,int32_t kmdstarti,int32_t kmdendi); uint256 komodo_calcMoM(int32_t height,int32_t MoMdepth); extern std::string ASSETCHAINS_SELFIMPORT; uint256 Parseuint256(char *hexstr); -int32_t GetSelfimportProof(std::string source,CMutableTransaction &mtx,CScript &scriptPubKey,TxProof &proof,uint64_t burnAmount,std::vector rawtx,uint256 txid,std::vector rawproof); +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 MakeGatewaysImportTx(uint64_t txfee, uint256 bindtxid, int32_t height, std::string refcoin, std::vectorproof, std::string rawburntx, int32_t ivout, uint256 burntxid); UniValue assetchainproof(const UniValue& params, bool fHelp) { @@ -256,6 +262,7 @@ UniValue migrate_createimporttransaction(const UniValue& params, bool fHelp) TxProof proof = GetAssetchainProof(burnTx.GetHash(),burnTx); CTransaction importTx = MakeImportCoinTransaction(proof, burnTx, payouts); + return HexStr(E_MARSHAL(ss << importTx)); } @@ -281,31 +288,122 @@ UniValue migrate_completeimporttransaction(const UniValue& params, bool fHelp) UniValue selfimport(const UniValue& params, bool fHelp) { - CMutableTransaction mtx; - std::string source; TxProof proof; CTransaction burnTx,tx; CTxOut burnOut; uint64_t burnAmount; uint256 txid,blockHash; std::vector vouts; std::vector rawtx,rawproof; CScript scriptPubKey; + UniValue result(UniValue::VOBJ); + CMutableTransaction sourceMtx, templateMtx; + std::string destaddr; + std::string source; + std::string rawsourcetx; + 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; + if ( ASSETCHAINS_SELFIMPORT.size() == 0 ) throw runtime_error("selfimport only works on -ac_import chains"); - if (fHelp || params.size() < 3 || params.size() > 5 ) - throw runtime_error("selfimport rawtx txid burnamount [rawproof source]\n\n" - "creates signed selfimport transaction"); - rawtx = ParseHex(params[0].get_str().c_str()); - txid = Parseuint256((char *)params[1].get_str().c_str()); // allow for txid != hash(rawtx) - burnAmount = atof(params[2].get_str().c_str()) * COIN + 0.00000000499999; - source = ASSETCHAINS_SELFIMPORT; - if ( params.size() >= 4 ) + + 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[3].get_str().c_str()); - if ( params.size() == 5 ) - source = params[4].get_str(); + rawproof = ParseHex(params[4].get_str().c_str()); + if ( params.size() == 6 ) + source = params[5].get_str(); + } */ + + + if (source == "BEAM") + { + if (ASSETCHAINS_BEAMPORT == 0) + return(-1); + // confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn + // return(0); + return -1; } - if ( GetSelfimportProof(source,mtx,scriptPubKey,proof,burnAmount,rawtx,txid,rawproof) < 0 ) - throw std::runtime_error("Failed validating selfimport"); - vouts = mtx.vout; - burnOut = MakeBurnOutput(burnAmount,0xffffffff,ASSETCHAINS_SELFIMPORT,vouts,rawproof); - mtx.vout.clear(); - mtx.vout.push_back(burnOut); - burnTx = mtx; - return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(proof,burnTx,vouts))); + else if (source == "CODA") + { + if (ASSETCHAINS_CODAPORT == 0) + return(-1); + // confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn + // return(0); + return -1; + } + else if (source == "PUBKEY") + { + + CTxDestination dest = DecodeDestination(destaddr.c_str()); + rawsourcetx = MakeSelfImportSourceTx(dest, burnAmount, sourceMtx); + sourcetxid = sourceMtx.GetHash(); + + // 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"); + + vouts = templateMtx.vout; + 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 + + 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, sourcetxid); + + result.push_back(Pair("hex", hextx)); + result.push_back(Pair("UsedRawtxVout", ivout)); // notify user about the used vout of rawtx + } + return result; } UniValue getNotarisationsForBlock(const UniValue& params, bool fHelp) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 98b5deccc..19ac60525 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -541,7 +541,8 @@ static const CRPCCommand vRPCCommands[] = /* Not shown in help */ { "hidden", "setmocktime", &setmocktime, true }, { "hidden", "test_ac", &test_ac, true }, - { "hidden", "test_heirmarker", &test_heirmarker, true }, + { "hidden", "test_heirmarker", &test_heirmarker, true }, + { "hidden", "test_proof", &test_proof, true }, { "hidden", "test_burntx", &test_burntx, true }, diff --git a/src/rpc/server.h b/src/rpc/server.h index 9cacce8ac..b41203df9 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -478,6 +478,6 @@ extern UniValue paxwithdraw(const UniValue& params, bool fHelp); extern UniValue test_ac(const UniValue& params, bool fHelp); extern UniValue test_heirmarker(const UniValue& params, bool fHelp); extern UniValue test_burntx(const UniValue& params, bool fHelp); - +extern UniValue test_proof(const UniValue& params, bool fHelp); #endif // BITCOIN_RPCSERVER_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5564c2000..f945b82fc 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -7883,8 +7883,11 @@ UniValue test_heirmarker(const UniValue& params, bool fHelp) cp = CCinit(&C, EVAL_HEIR); return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, opret)); + + } + UniValue test_burntx(const UniValue& params, bool fHelp) { // make fake token tx: @@ -7927,3 +7930,52 @@ UniValue test_burntx(const UniValue& params, bool fHelp) CCaddr2set(cp, EVAL_TOKENS, unspPk, tokenpriv, unspendableTokenAddr); return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, EncodeTokenOpRet(tokenid, voutPubkeys, CScript()))); } + +UniValue test_proof(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); + std::vectorproof; + + if (fHelp || (params.size() != 2)) + throw runtime_error("incorrect params\n"); + + + proof = ParseHex(params[0].get_str()); + uint256 cointxid = Parseuint256((char *)params[1].get_str().c_str()); + + std::vector txids; + + CMerkleBlock merkleBlock; + if (!E_UNMARSHAL(proof, ss >> merkleBlock)) { + result.push_back(Pair("error", "could not unmarshal proof")); + return result; + } + uint256 merkleRoot = merkleBlock.txn.ExtractMatches(txids); + + result.push_back(Pair("source_root", merkleRoot.GetHex())); + + for (int i = 0; i < txids.size(); i++) + std::cerr << "merkle block txid=" << txids[0].GetHex() << std::endl; + + + std::vector vMatches(txids.size()); + for (auto v : vMatches) v = true; + CPartialMerkleTree verifTree(txids, vMatches); + + result.push_back(Pair("verif_root", verifTree.ExtractMatches(txids).GetHex())); + + if (std::find(txids.begin(), txids.end(), cointxid) == txids.end()) { + fprintf(stderr, "invalid proof for this cointxid\n"); + } + + std::vector vMerkleTree; + bool f; + ::BuildMerkleTree(&f, txids, vMerkleTree); + + std::vector vMerkleBranch = ::GetMerkleBranch(0, txids.size(), vMerkleTree); + + uint256 ourResult = SafeCheckMerkleBranch(zeroid, vMerkleBranch, 0); + result.push_back(Pair("SafeCheckMerkleBranch", ourResult.GetHex())); + + return result; +} From 7b312f6ce680977b12690fa11be83cfe9fd3c02b Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 16 Feb 2019 21:59:21 +0500 Subject: [PATCH 02/17] added burn tx nExpiryHeight validation --- src/cc/import.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/cc/import.cpp b/src/cc/import.cpp index dbbf7832f..1b49f5c94 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -371,6 +371,12 @@ int32_t CheckPUBKEYimport(TxProof proof,std::vector rawproof,CTransacti return -1; } + // might be malleable: + if (burnTx.nExpiryHeight != sourcetx.nExpiryHeight) { + LOGSTREAM("importcoin", CCLOG_INFO, stream << "burntx nExpiryHeight incorrect for source txid=" << sourcetxid.GetHex() << std::endl); + return -1; + } + //ac_pubkey check: if (CheckVin0PubKey(sourcetx) < 0) { return -1; From 3c3531627f25c6a6d94fc6aef07dcbb6e4150b66 Mon Sep 17 00:00:00 2001 From: dimxy Date: Sat, 16 Feb 2019 22:15:55 +0500 Subject: [PATCH 03/17] comment added --- 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 1b49f5c94..25bed49df 100644 --- a/src/cc/import.cpp +++ b/src/cc/import.cpp @@ -415,7 +415,7 @@ bool Eval::ImportCoin(const std::vector params,const CTransaction &impo return Invalid("invalid-params"); // Control all aspects of this transaction // It should not be at all malleable - if (MakeImportCoinTransaction(proof, burnTx, payouts, importTx.nExpiryHeight).GetHash() != importTx.GetHash()) + if (MakeImportCoinTransaction(proof, burnTx, payouts, importTx.nExpiryHeight).GetHash() != importTx.GetHash()) // ExistsImportTombstone prevents from duplication return Invalid("non-canonical"); // burn params if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof)) From 8ea12e7dde906edc9d0e4342929bc13c7eb70b92 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:02:10 -1100 Subject: [PATCH 04/17] Test --- src/cc/rogue/rogue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/rogue/rogue.c b/src/cc/rogue/rogue.c index bc576dabf..6583725f4 100644 --- a/src/cc/rogue/rogue.c +++ b/src/cc/rogue/rogue.c @@ -250,6 +250,7 @@ int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t nu rs->restoring = 1; //fprintf(stderr,"restore player packsize.%d HP.%d\n",rs->P.packsize,rs->P.hitpoints); } + globalR = *rs; uint32_t starttime = (uint32_t)time(NULL); rogueiterate(rs); if ( 0 ) @@ -760,7 +761,7 @@ my_exit(int st) exit(st); else if ( counter++ < 10 ) { - fprintf(stderr,"would have exit.(%d)\n",st); + fprintf(stderr,"would have exit.(%d) sleeptime.%d\n",st,globalR.sleeptime); globalR.replaydone = 1; } } From ef554cc4744b53eda75dafeea3698e94328eb042 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:03:55 -1100 Subject: [PATCH 05/17] -print and pause --- src/cc/rogue/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/rogue/io.c b/src/cc/rogue/io.c index 525550e67..9842ba353 100644 --- a/src/cc/rogue/io.c +++ b/src/cc/rogue/io.c @@ -162,7 +162,7 @@ readchar(struct rogue_state *rs) c = rs->keystrokes[rs->ind++]; while ( c == 'Q' && rs->ind < rs->numkeys ) { - fprintf(stderr,"Got 'Q' next (%c)\n",rs->keystrokes[rs->ind]); sleep(2); + //fprintf(stderr,"Got 'Q' next (%c)\n",rs->keystrokes[rs->ind]); sleep(2); if ( rs->keystrokes[rs->ind] == 'y' ) return(c); rs->ind++; From 85d4e67ea779ef417ffa07567d4639d10e897884 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:16:03 -1100 Subject: [PATCH 06/17] -print --- src/cc/rogue/cursesd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/rogue/cursesd.c b/src/cc/rogue/cursesd.c index 30cc54ec9..02a80c470 100644 --- a/src/cc/rogue/cursesd.c +++ b/src/cc/rogue/cursesd.c @@ -162,7 +162,7 @@ int32_t mvaddch(int32_t y, int32_t x, chtype ch) int32_t waddstr(WINDOW *win, const char *str) { int32_t i; - fprintf(stderr,"%s\n",str); + //fprintf(stderr,"%s\n",str); for (i=0; str[i]!=0; i++) waddch(win,str[i]); return(0); From 26f77ab47dc2a66b9529921794bebadf9951ac5b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:29:45 -1100 Subject: [PATCH 07/17] -sleep --- src/cc/rogue/rogue.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc/rogue/rogue.c b/src/cc/rogue/rogue.c index 6583725f4..c2f1d9829 100644 --- a/src/cc/rogue/rogue.c +++ b/src/cc/rogue/rogue.c @@ -595,7 +595,7 @@ playit(struct rogue_state *rs) { if ( rs->replaydone != 0 ) { - if ( rs->sleeptime != 0 ) + if ( 0 && rs->sleeptime != 0 ) sleep(3); return; } @@ -623,7 +623,7 @@ int32_t _quit() //fprintf(stderr,"inside quit(%d)\n",sig); getyx(curscr, oy, ox); msg(rs,"really quit?"); - sleep(1); + //sleep(1); if ( (c= readchar(rs)) == 'y') { if ( rs->guiflag != 0 ) From 9ef4ca17230036e43607999f0f9d6f06ff3ee282 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:33:24 -1100 Subject: [PATCH 08/17] Validation prints --- src/cc/rogue_rpc.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 62f653685..d0ed66cbb 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1235,6 +1235,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C case 'K': // keystrokes case 'H': // win case 'Q': // bailout + fprintf(stderr,"ht.%d rogue.(%c)\n",height,script[1]); return(true); break; default: @@ -1244,6 +1245,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C } else if ( script[0] == EVAL_TOKENS ) { + fprintf(stderr,"ht.%d tokens.(%c)\n",height,script[1]); if ( script[1] == 'c' ) { return(true); From 9a48b245d436297903ae8f44292f9332deee427b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:46:14 -1100 Subject: [PATCH 09/17] Remove minstrength check --- src/cc/rogue/init.c | 4 +--- src/cc/rogue_rpc.cpp | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/cc/rogue/init.c b/src/cc/rogue/init.c index 6ff0a71c0..62998889d 100644 --- a/src/cc/rogue/init.c +++ b/src/cc/rogue/init.c @@ -28,9 +28,7 @@ void restore_player(struct rogue_state *rs) //rs->P.gold = purse; max_hp = rs->P.hitpoints; pstats.s_str = rs->P.strength & 0xffff; - max_stats.s_str = rs->P.strength >> 16; - if ( max_stats.s_str < 12 ) - max_stats.s_str = 12; + max_stats.s_str = (rs->P.strength >> 16) & 0xffff; if ( pstats.s_str > max_stats.s_str ) pstats.s_str = max_stats.s_str; pstats.s_lvl = rs->P.level; diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index d0ed66cbb..068847c93 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1226,9 +1226,18 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C if ( vopret.size() > 2 ) { script = (uint8_t *)vopret.data(); + if ( script[0] == EVAL_TOKENS ) + { + if ( script[1] == 'c' ) + { + } + else if ( script[1] == 't' ) + { + } else return eval->Invalid("illegal tokens funcid"); + } if ( script[0] == EVAL_ROGUE ) { - switch ( script[1] ) + switch ( funcid ) { case 'G': // newgame case 'R': // register @@ -1242,18 +1251,6 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C return eval->Invalid("illegal rogue funcid"); break; } - } - else if ( script[0] == EVAL_TOKENS ) - { - fprintf(stderr,"ht.%d tokens.(%c)\n",height,script[1]); - if ( script[1] == 'c' ) - { - return(true); - } - else - { - return(true); - } } else return eval->Invalid("illegal evalcode"); } else return eval->Invalid("opret too small"); } else return eval->Invalid("not enough vouts"); From eff9ec93e24fbf2be824a4ef68e194933854de72 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:47:59 -1100 Subject: [PATCH 10/17] Backwards compatibility --- src/cc/rogue/init.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cc/rogue/init.c b/src/cc/rogue/init.c index 62998889d..1a5faa9ce 100644 --- a/src/cc/rogue/init.c +++ b/src/cc/rogue/init.c @@ -28,7 +28,8 @@ void restore_player(struct rogue_state *rs) //rs->P.gold = purse; max_hp = rs->P.hitpoints; pstats.s_str = rs->P.strength & 0xffff; - max_stats.s_str = (rs->P.strength >> 16) & 0xffff; + if ( (max_stats.s_str= (rs->P.strength >> 16) & 0xffff) == 0 ) + max_stats.s_str = 16; if ( pstats.s_str > max_stats.s_str ) pstats.s_str = max_stats.s_str; pstats.s_lvl = rs->P.level; From 2e1e7f8c7ba42670af2156759e38fc38fb0529aa Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 17 Feb 2019 23:52:07 -1100 Subject: [PATCH 11/17] Fix num_pack --- src/cc/rogue/pack.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/cc/rogue/pack.c b/src/cc/rogue/pack.c index 2f683441b..37072bf93 100644 --- a/src/cc/rogue/pack.c +++ b/src/cc/rogue/pack.c @@ -252,7 +252,10 @@ int32_t num_packitems() THING *list = pack; int32_t type = 0,n = 0; for (; list != NULL; list = next(list)) - n++; + { + if (!list->o_packch) + n++; + } return(n); } From 76c397d4d1137a44b6f7b8026cfa9c898222c101 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 18 Feb 2019 00:00:06 -1100 Subject: [PATCH 12/17] Rework validation --- src/cc/rogue/pack.c | 16 ++++++++-------- src/cc/rogue_rpc.cpp | 9 +++++++-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/cc/rogue/pack.c b/src/cc/rogue/pack.c index 37072bf93..392159fb5 100644 --- a/src/cc/rogue/pack.c +++ b/src/cc/rogue/pack.c @@ -52,9 +52,9 @@ add_pack(struct rogue_state *rs,THING *obj, bool silent) if (pack == NULL) { - pack = obj; - obj->o_packch = pack_char(); - inpack++; + pack = obj; + obj->o_packch = pack_char(); + inpack++; } else { @@ -291,11 +291,11 @@ inventory(struct rogue_state *rs,THING *list, int type) // fprintf(stderr,"n_objs.%d vs inpack.%d\n",n_objs,inpack), sleep(2); if (n_objs == 0) { - if (terse) - msg(rs,type == 0 ? (char *)"empty handed" : (char *)"nothing appropriate"); - else - msg(rs,type == 0 ? (char *)"you are empty handed" : (char *)"you don't have anything appropriate"); - return FALSE; + if (terse) + msg(rs,type == 0 ? (char *)"empty handed" : (char *)"nothing appropriate"); + else + msg(rs,type == 0 ? (char *)"you are empty handed" : (char *)"you don't have anything appropriate"); + return FALSE; } end_line(rs); return TRUE; diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index 068847c93..c4a142ba1 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1226,16 +1226,21 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C if ( vopret.size() > 2 ) { script = (uint8_t *)vopret.data(); - if ( script[0] == EVAL_TOKENS ) + funcid = script[1]; + if ( (e= script[0]) == EVAL_TOKENS ) { if ( script[1] == 'c' ) { + e = EVAL_ROGUE; + funcid = 'Q'; } else if ( script[1] == 't' ) { + e = EVAL_ROGUE; + funcid = 'Q'; } else return eval->Invalid("illegal tokens funcid"); } - if ( script[0] == EVAL_ROGUE ) + if ( e == EVAL_ROGUE ) { switch ( funcid ) { From 27002ce1f2f10f12baef75e4fb30c898370c8d9b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 18 Feb 2019 00:07:45 -1100 Subject: [PATCH 13/17] -print --- src/cc/assets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 28adf9be6..f42c4fda3 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -177,7 +177,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti // find single-eval token user cc addr: //GetCCaddress(cpTokens, signleEvalTokensCCaddr, pubkey2pk(origpubkey)); - fprintf(stderr,"AssetValidate (%c)\n",funcid); + //fprintf(stderr,"AssetValidate (%c)\n",funcid); if( funcid != 'o' && funcid != 'x' && eval->GetTxUnconfirmed(assetid, createTx, hashBlock) == 0 ) return eval->Invalid("cant find asset create txid"); From 2d98e3a0e58072fac0eb866dfbcf2c36d3c8bc2e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 18 Feb 2019 00:39:21 -1100 Subject: [PATCH 14/17] Decode all ospreys --- src/cc/rogue_rpc.cpp | 69 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index c4a142ba1..ac63dea42 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1218,7 +1218,7 @@ UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { - CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid; int32_t i,ind,errflag,dispflag,score,numvouts; CTransaction vintx; uint256 hashBlock; + CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid; int32_t i,maxplayers,decoded=0,regslot,ind,errflag,dispflag,score,numvouts; CTransaction vintx; CPubKey pk; uint256 hashBlock,gametxid,tokenid,batontxid; int64_t buyin; std::vector playerdata,keystrokes; std::string symbol,pname; if ( (numvouts= tx.vout.size()) > 1 ) { scriptPubKey = tx.vout[numvouts-1].scriptPubKey; @@ -1229,30 +1229,67 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C funcid = script[1]; if ( (e= script[0]) == EVAL_TOKENS ) { - if ( script[1] == 'c' ) + if ( (funcid= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) == 0 ) { - e = EVAL_ROGUE; - funcid = 'Q'; - } - else if ( script[1] == 't' ) - { - e = EVAL_ROGUE; - funcid = 'Q'; - } else return eval->Invalid("illegal tokens funcid"); + if ( (funcid= rogue_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) == 0 ) + { + funcid = 'Q'; + fprintf(stderr,"ht.%d couldnt decode tokens opret\n",height); + } else e = EVAL_ROGUE, decoded = 1; + } else e = EVAL_ROGUE, decoded = 1; } if ( e == EVAL_ROGUE ) { + if ( decoded == 0 ) + { + switch ( funcid ) + { + case 'G': + if ( (funcid= rogue_newgameopreturndecode(buyin,maxplayers,scriptPubKey)) != 'G' ) + return eval->Invalid("couldnt decode newgame opret"); + // validate newgame tx + return(true); + break; + case 'R': + if ( (funcid= rogue_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) != 'R' ) + return eval->Invalid("couldnt decode register opret"); + break; + case 'K': + if ( (funcid= rogue_keystrokesopretdecode(gametxid,batontxid,pk,keystrokes,scriptPubKey)) != 'K' ) + return eval->Invalid("couldnt decode keystrokes opret"); + // validate keystrokes are from the correct pk. might need to add vin + return(true); + break; + case 'H': case 'Q': + if ( (f= rogue_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) != funcid ) + return eval->Invalid("couldnt decode H/Q opret"); + break; + default: + return eval->Invalid("illegal rogue non-decoded funcid"); + break; + } + } switch ( funcid ) { - case 'G': // newgame - case 'R': // register - case 'K': // keystrokes - case 'H': // win - case 'Q': // bailout - fprintf(stderr,"ht.%d rogue.(%c)\n",height,script[1]); + case 'R': + // validate register: within 60 blocks, not duplicate, etc. + return(true); + break; + case 'H': // fall through + case 'Q': + // make sure any playerdata is reproduced via replay + if ( funcid == 'Q' ) + { + // validate bailout constraints + } + else // 'H' + { + // validate winner constraints + } return(true); break; default: + fprintf(stderr,"ht.%d rogue.(%c)\n",height,script[1]); return eval->Invalid("illegal rogue funcid"); break; } From bec0d4935f6227df401270e3cd779f05657fd65b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 18 Feb 2019 00:39:56 -1100 Subject: [PATCH 15/17] Playertxid --- src/cc/rogue_rpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index ac63dea42..06d2b63b8 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -1218,7 +1218,7 @@ UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) { - CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid; int32_t i,maxplayers,decoded=0,regslot,ind,errflag,dispflag,score,numvouts; CTransaction vintx; CPubKey pk; uint256 hashBlock,gametxid,tokenid,batontxid; int64_t buyin; std::vector playerdata,keystrokes; std::string symbol,pname; + CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid; int32_t i,maxplayers,decoded=0,regslot,ind,errflag,dispflag,score,numvouts; CTransaction vintx; CPubKey pk; uint256 hashBlock,gametxid,tokenid,batontxid,playertxid; int64_t buyin; std::vector playerdata,keystrokes; std::string symbol,pname; if ( (numvouts= tx.vout.size()) > 1 ) { scriptPubKey = tx.vout[numvouts-1].scriptPubKey; From 562e99fc96d91c8d796580ca3d688d34d8aa6884 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 18 Feb 2019 00:51:21 -1100 Subject: [PATCH 16/17] Do total items --- src/cc/rogue/pack.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cc/rogue/pack.c b/src/cc/rogue/pack.c index 392159fb5..4858afcdd 100644 --- a/src/cc/rogue/pack.c +++ b/src/cc/rogue/pack.c @@ -250,12 +250,16 @@ pack_char() int32_t num_packitems() { THING *list = pack; - int32_t type = 0,n = 0; + int32_t type = 0,n = 0,total = 0; for (; list != NULL; list = next(list)) { - if (!list->o_packch) + if ( list->o_packch != 0 ) + { n++; + total += list->o_count; + } } + fprintf(stderr,"total.%d vs %d inventory letters\n",total,n); return(n); } From 437af05de66e9e0822c1472eef335425bcb49883 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 18 Feb 2019 00:53:23 -1100 Subject: [PATCH 17/17] Test --- src/cc/rogue/pack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cc/rogue/pack.c b/src/cc/rogue/pack.c index 4858afcdd..8fc488389 100644 --- a/src/cc/rogue/pack.c +++ b/src/cc/rogue/pack.c @@ -259,7 +259,7 @@ int32_t num_packitems() total += list->o_count; } } - fprintf(stderr,"total.%d vs %d inventory letters\n",total,n); + fprintf(stderr,"total.%d vs %d inventory letters\n",total,n); sleep(1); return(n); }