diff --git a/src/cc/CCMarmara.h b/src/cc/CCMarmara.h index 8fbe25b62..79372fa27 100644 --- a/src/cc/CCMarmara.h +++ b/src/cc/CCMarmara.h @@ -23,10 +23,15 @@ #define MARMARA_GROUPSIZE 60 #define MARMARA_MINLOCK (1440 * 3 * 30) #define MARMARA_MAXLOCK (1440 * 24 * 30) + uint64_t komodo_block_prg(uint32_t nHeight); +int32_t MarmaraGetcreatetxid(uint256 &createtxid,uint256 txid); + UniValue MarmaraPoolPayout(uint64_t txfee,int32_t firstheight,double perc,char *jsonstr); // [[pk0, shares0], [pk1, shares1], ...] -UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::string currency,int32_t matures,uint256 createtxid); -UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey senderpk,int64_t amount,std::string currency,int32_t matures,uint256 createtxid); +UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::string currency,int32_t matures,uint256 batontxid); +UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t amount,std::string currency,int32_t matures,uint256 approvaltxid,uint256 batontxid); +UniValue MarmaraInfo(CPubKey refpk,int32_t firstheight,int32_t lastheight,int64_t minamount,int64_t maxamount,std::string currency); +UniValue MarmaraCrediloop(uint256 batontxid); bool MarmaraValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index aaeadcc61..0744156a5 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -56,6 +56,8 @@ extern uint32_t ASSETCHAINS_CC; extern char ASSETCHAINS_SYMBOL[]; extern std::string CCerror; +#define CC_MAXVINS 1024 + #define SMALLVAL 0.000000000000001 #ifndef _BITS256 #define _BITS256 diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index 32d525517..a70d4f038 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -42,7 +42,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran { auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); CTransaction vintx; std::string hex; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0; - int64_t utxovalues[64],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; + int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0; int32_t i,utxovout,n,err = 0; char myaddr[64],destaddr[64],unspendable[64]; uint8_t *privkey,myprivkey[32],unspendablepriv[32],*msg32 = 0; CC *mycond=0,*othercond=0,*othercond2=0,*othercond3=0,*cond; CPubKey unspendablepk; n = mtx.vout.size(); @@ -52,7 +52,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran normaloutputs += mtx.vout[i].nValue; totaloutputs += mtx.vout[i].nValue; } - if ( (n= mtx.vin.size()) > 64 ) + if ( (n= mtx.vin.size()) > CC_MAXVINS ) { fprintf(stderr,"FinalizeCCTx: %d is too many vins\n",n); return("0"); diff --git a/src/cc/marmara.cpp b/src/cc/marmara.cpp index 9a5a1e6ef..ba238e755 100644 --- a/src/cc/marmara.cpp +++ b/src/cc/marmara.cpp @@ -18,6 +18,25 @@ /* Marmara CC is for the MARMARA project + 'R': two forms for initial issuance and for accepting existing + vins normal + vout0 approval to senderpk (issuer or owner of baton) + + 'I' + vin0 approval from 'R' + vins1+ normal + vout0 baton to 1st receiverpk + vout1 marker to Marmara so all issuances can be tracked (spent when loop is closed) + + 'T' + vin0 approval from 'R' + vin1 baton from 'I'/'T' + vins2+ normal + vout0 baton to next receiverpk (following the unspent baton back to original is the credit loop) + + 'S' + vins CC utxos from credit loop + */ // start of consensus code @@ -138,6 +157,29 @@ CScript MarmaraLoopOpret(uint8_t funcid,uint256 createtxid,CPubKey senderpk,int6 return(opret); } +uint8_t MarmaraDecodeLoopOpret(const CScript scriptPubKey,uint256 &createtxid,CPubKey &senderpk,int64_t &amount,int32_t &matures,std::string ¤cy) +{ + std::vector vopret; uint8_t *script,e,f; + GetOpReturnData(scriptPubKey, vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> createtxid; ss >> senderpk; ss >> amount; ss >> matures; ss >> currency) != 0 ) + { + return(f); + } + return(0); +} + +int32_t MarmaraGetcreatetxid(uint256 &createtxid,uint256 txid) +{ + CTransaction tx; uint256 hashBlock; int32_t numvouts,matures; std::string currency; CPubKey senderpk; int64_t amount; + if ( myGetTransaction(batontxid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + if ( (funcid= MarmaraDecodeLoopOpret(tx.vout[numvouts-1].scriptPubKey,createtxid,senderpk,amount,matures,currency)) == 'I' || funcid == 'T' ) + return(0); + } + return(-1); +} + CScript Marmara_scriptPubKey(int32_t height,CPubKey pk) { CTxOut ccvout; @@ -297,16 +339,51 @@ int64_t AddMarmaraCoinbases(struct CCcontract_info *cp,CMutableTransaction &mtx, return(totalinputs); } -UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::string currency,int32_t matures,uint256 createtxid) +int32_t MarmaraGetCreditloops(int64_t &totalamount,std::vector &issuances,struct CCcontract_info *cp,int32_t firstheight,int32_t lastheight,int64_t minamount,int64_t maxamount,CPubKey refpk,std::string refcurrency) +{ + char coinaddr[64]; CPubKey Marmarapk,senderpk; int64_t amount; uint256 createtxid,txid,hashBlock; CTransaction tx; int32_t numvouts,unlockht,ht,vout,matures,n=0; + std::vector > unspentOutputs; + Marmarapk = GetUnspendable(cp,0); + GetCCaddress(cp,coinaddr,Marmarapk); + SetCCunspents(unspentOutputs,coinaddr); + //fprintf(stderr,"check coinaddr.(%s)\n",coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //fprintf(stderr,"txid.%s/v%d\n",txid.GetHex().c_str(),vout); + if ( vout == 1 && GetTransaction(txid,tx,hashBlock,false) != 0 ) + { + if ( tx.IsCoinBase() == 0 && (numvouts= tx.vout.size()) > 2 && tx.vout[numvouts - 1].nValue == 0 ) + { + if ( MarmaraDecodeLoopOpret(tx.vout[numvouts-1].scriptPubKey,createtxid,senderpk,amount,matures,currency) == 'I' ) + { + n++; + if ( currency == refcurrency && matures >= firstheight && matures <= lastheight && amount >= minamount && amount <= maxamount && (refpk.size() == 0 || senderpk == refpk) ) + { + issuances.push_back(txid); + totalamount += amount; + } + } + } + } else fprintf(stderr,"error getting tx\n"); + } + return(n); +} + +UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::string currency,int32_t matures,uint256 batontxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); CPubKey mypk; struct CCcontract_info *cp,C; std::string rawtx; char *errorstr=0; int32_t needbaton = 0; + UniValue result(UniValue::VOBJ); CPubKey mypk; struct CCcontract_info *cp,C; std::string rawtx; char *errorstr=0; uint256 createtxid; int32_t needbaton = 0; cp = CCinit(&C,EVAL_MARMARA); if ( txfee == 0 ) txfee = 10000; // check for batonownership by senderpk and parameters match createtxid mypk = pubkey2pk(Mypubkey()); - if ( currency != "MARMARA" ) + memset(&createtxid,0,sizeof(createtxid)); + if ( batontxid != zeroid && MarmaraGetcreatetxid(createtxid,batontxid) < 0 ) + errorstr = (char *)"cant get createtxid from batontxid"; + else if ( currency != "MARMARA" ) errorstr = (char *)"for now, only MARMARA loops are supported"; else if ( amount < txfee ) errorstr = (char *)"amount must be for more than txfee"; @@ -346,16 +423,20 @@ UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::stri return(result); } -UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t amount,std::string currency,int32_t matures,uint256 createtxid) +UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t amount,std::string currency,int32_t matures,uint256 approvaltxid,uint256 batontxid) { CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); CPubKey mypk; struct CCcontract_info *cp,C; std::string rawtx; char *errorstr=0; + UniValue result(UniValue::VOBJ); CPubKey mypk,Marmarapk; struct CCcontract_info *cp,C; std::string rawtx; uint256 createtxid; char *errorstr=0; cp = CCinit(&C,EVAL_MARMARA); if ( txfee == 0 ) txfee = 10000; - // make sure if transfer that it is not too late + // make sure receiverpk is unique to creditloop + // make sure less than maxlength + Marmarapk = GetUnspendable(cp,0); mypk = pubkey2pk(Mypubkey()); - if ( currency != "MARMARA" ) + if ( MarmaraGetcreatetxid(createtxid,approvaltxid) < 0 ) + errorstr = (char *)"cant get createtxid from approvaltxid"; + else if ( currency != "MARMARA" ) errorstr = (char *)"for now, only MARMARA loops are supported"; else if ( amount < txfee ) errorstr = (char *)"amount must be for more than txfee"; @@ -363,10 +444,15 @@ UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t a errorstr = (char *)"it must mature in the future"; if ( errorstr == 0 ) { - if ( AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) + mtx.vin.push_back(CTxIn(approvaltxid,0,CScript())); + if ( funcid == 'T' ) + mtx.vin.push_back(CTxIn(batontxid,0,CScript())); + if ( funcid == 'I' || AddNormalinputs(mtx,mypk,2*txfee,1) > 0 ) { errorstr = (char *)"couldnt finalize CCtx"; mtx.vout.push_back(MakeCC1vout(EVAL_MARMARA,txfee,receiverpk)); + if ( funcid == 'I' ) + mtx.vout.push_back(MakeCC1vout(EVAL_MARMARA,txfee,Marmarapk)); rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,MarmaraLoopOpret(funcid,createtxid,receiverpk,amount,matures,currency)); if ( rawtx.size() > 0 ) errorstr = 0; @@ -385,6 +471,9 @@ UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t a char str[2]; str[0] = funcid, str[1] = 0; result.push_back(Pair("funcid",str)); result.push_back(Pair("createtxid",createtxid.GetHex())); + result.push_back(Pair("approvaltxid",approvaltxid.GetHex())); + if ( funcid == 'T' ) + result.push_back(Pair("batontxid",batontxid.GetHex())); result.push_back(Pair("receiverpk",HexStr(receiverpk))); result.push_back(Pair("amount",ValueFromAmount(amount))); result.push_back(Pair("matures",matures)); @@ -393,32 +482,64 @@ UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t a return(result); } -std::string MarmaraFund(uint64_t txfee,int64_t funds) +// get creditloop pubkeys + +UniValue Marmara(uint64_t txfee,uint256 batontxid) { - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey mypk,Marmarapk; CScript opret; struct CCcontract_info *cp,C; + UniValue result(UniValue::VOBJ); int64_t avail,amount,paid=0; int32_t i,n = 0; uint256 txid,*revcreditloop=0; CPubKey Marmarapk; struct CCcontract_info *cp,C; + result.push_back(Pair("result","success")); cp = CCinit(&C,EVAL_MARMARA); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); Marmarapk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) + txid = batontxid; + while ( txid.hasprev() != 0 ) { - mtx.vout.push_back(MakeCC1vout(EVAL_MARMARA,funds,Marmarapk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); + txid = txid.prev(); + // check for unique, else error + revcreditloop[n++] = txid; } - return(""); + for (i=0; i= amount ) + { + change = (amount - paid); + break; + } + } + + return(result); } -UniValue MarmaraInfo() +UniValue MarmaraInfo(CPubKey refpk,int32_t firstheight,int32_t lastheight,int64_t minamount,int64_t maxamount,std::string currency) { - UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - CPubKey Marmarapk; struct CCcontract_info *cp,C; int64_t funding; + UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n; int64_t totalamount=0; std::vector issuances; + CPubKey Marmarapk; struct CCcontract_info *cp,C; result.push_back(Pair("result","success")); - result.push_back(Pair("name","Marmara")); + if ( refpk.size() == 33 ) + result.push_back(Pair("issuer",HexStr(refpk))); + if ( currency.size() == 0 ) + currency = (char *)"MARMARA"; + if ( firstheight <= lastheight ) + firstheight = 0, lastheight = (1 << 30); + if ( minamount <= maxamount ) + minamount = 0, maxamount = (1LL << 60); + result.push_back(Pair("firstheight",firstheight)); + result.push_back(Pair("lastheight",lastheight)); + result.push_back(Pair("minamount",ValueFromAmount(minamount))); + result.push_back(Pair("maxamount",ValueFromAmount(maxamount))); + result.push_back(Pair("currency",currency)); cp = CCinit(&C,EVAL_MARMARA); Marmarapk = GetUnspendable(cp,0); + if ( (n= MarmaraGetCreditloops(totalamount,issuances,cp,firstheight,lastheight,minamount,maxamount,refpk,currency)) > 0 ) + { + result.push_back(Pair("n",n)); + matches = (int32_t)issuances.size(); + result.push_back(Pair("matches",matches)); + for (i=0; i senderpub; int64_t amount; int32_t matures; std::string currency; + UniValue result(UniValue::VOBJ); uint256 batontxid; std::vector senderpub; int64_t amount; int32_t matures; std::string currency; if ( fHelp || (params.size() != 5 && params.size() != 4) ) { // 1st marmarareceive 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 7.5 MARMARA 1440 // after marmarareceive 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 7.5 MARMARA 1440 - throw runtime_error("marmarareceive senderpk amount currency matures createtxid\n"); + throw runtime_error("marmarareceive senderpk amount currency matures batontxid\n"); } if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - memset(&createtxid,0,sizeof(createtxid)); + memset(&batontxid,0,sizeof(batontxid)); senderpub = ParseHex(params[0].get_str().c_str()); if (senderpub.size()!= 33) { @@ -5570,17 +5570,17 @@ UniValue marmara_receive(const UniValue& params, bool fHelp) currency = params[2].get_str(); matures = atol(params[3].get_str().c_str()) + chainActive.LastTip()->GetHeight() + 1; if ( params.size() == 5 ) - createtxid = Parseuint256((char *)params[4].get_str().c_str()); - return(MarmaraReceive(0,pubkey2pk(senderpub),amount,currency,matures,createtxid)); + batontxid = Parseuint256((char *)params[4].get_str().c_str()); + return(MarmaraReceive(0,pubkey2pk(senderpub),amount,currency,matures,batontxid)); } UniValue marmara_issue(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); uint256 createtxid; std::vector receiverpub; int64_t amount; int32_t matures; std::string currency; + UniValue result(UniValue::VOBJ); uint256 approvaltxid; std::vector receiverpub; int64_t amount; int32_t matures; std::string currency; if ( fHelp || params.size() != 5 ) { // marmaraissue 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 7.5 MARMARA 2693 e5b1ef8ec90e981d3011c8e024cef869b69af2d4dd6837d1ab1d394d3730b7cb - throw runtime_error("marmaraissue receiverpk amount currency matures createtxid\n"); + throw runtime_error("marmaraissue receiverpk amount currency matures approvaltxid\n"); } if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -5593,8 +5593,8 @@ UniValue marmara_issue(const UniValue& params, bool fHelp) amount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999; currency = params[2].get_str(); matures = atol(params[3].get_str().c_str()); - createtxid = Parseuint256((char *)params[4].get_str().c_str()); - return(MarmaraIssue(0,'I',pubkey2pk(receiverpub),amount,currency,matures,createtxid)); + approvaltxid = Parseuint256((char *)params[4].get_str().c_str()); + return(MarmaraIssue(0,'I',pubkey2pk(receiverpub),amount,currency,matures,approvaltxid,zeroid)); } UniValue marmara_transfer(const UniValue& params, bool fHelp) @@ -5603,7 +5603,7 @@ UniValue marmara_transfer(const UniValue& params, bool fHelp) if ( fHelp || params.size() != 5 ) { // marmaratransfer 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 7.5 MARMARA 2693 e5b1ef8ec90e981d3011c8e024cef869b69af2d4dd6837d1ab1d394d3730b7cb - throw runtime_error("marmaratransfer receiverpk amount currency matures createtxid\n"); + throw runtime_error("marmaratransfer receiverpk amount currency matures batontxid\n"); } if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); @@ -5616,8 +5616,53 @@ UniValue marmara_transfer(const UniValue& params, bool fHelp) amount = atof(params[1].get_str().c_str()) * COIN + 0.00000000499999; currency = params[2].get_str(); matures = atol(params[3].get_str().c_str()); - createtxid = Parseuint256((char *)params[4].get_str().c_str()); - return(MarmaraIssue(0,'T',pubkey2pk(receiverpub),amount,currency,matures,createtxid)); + batontxid = Parseuint256((char *)params[4].get_str().c_str()); + if ( MarmaraGetcreatetxid(createtxid,batontxid) < 0 ) + throw runtime_error("invalid batontxid"); + return(MarmaraIssue(0,'T',pubkey2pk(receiverpub),amount,currency,matures,createtxid,batontxid)); +} + +UniValue marmara_info(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); CPubKey issuerpk; std::vector issuerpub; int64_t minamount,maxamount; int32_t firstheight,lastheight; std::string currency; + if ( fHelp || params.size() < 4 || params.size() > 6 ) + { + throw runtime_error("marmarainfo firstheight lastheight minamount maxamount [currency issuerpk]\n"); + } + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + firstheight = atol(params[0].get_str().c_str()); + lastheight = atol(params[1].get_str().c_str()); + minamount = atof(params[2].get_str().c_str()) * COIN + 0.00000000499999; + maxamount = atof(params[3].get_str().c_str()) * COIN + 0.00000000499999; + if ( params.size() >= 5 ) + currency = params[4].get_str(); + if ( params.size() == 6 ) + { + issuerpub = ParseHex(params[5].get_str().c_str()); + if ( issuerpub.size()!= 33 ) + { + ERR_RESULT("invalid issuer pubkey"); + return result; + } + issuerpk = pubkey2pk(issuerpub); + } + result = MarmaraInfo(issuerpk,firstheight,lastheight,minamount,maxamount,currency); + return(result); +} + +UniValue marmara_creditloop(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); uint256 createtxid; std::vector receiverpub; int64_t amount; int32_t matures; std::string currency; + if ( fHelp || params.size() != 5 ) + { + // marmaratransfer 039433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775 7.5 MARMARA 2693 e5b1ef8ec90e981d3011c8e024cef869b69af2d4dd6837d1ab1d394d3730b7cb + throw runtime_error("marmaratransfer receiverpk amount currency matures batontxid\n"); + } + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + //UniValue MarmaraCrediloop(uint256 batontxid); + return(result); } UniValue channelslist(const UniValue& params, bool fHelp)