From 10078e85a9dd67fb1b06ba2da31848b0856314f0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 29 Jul 2018 03:54:39 -1100 Subject: [PATCH] +print --- src/cc/dice.cpp | 490 +++++++++++++++++++++++++++++++++++++-------- src/cc/rewards.cpp | 3 +- 2 files changed, 411 insertions(+), 82 deletions(-) diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index 159ac7a8c..55e7aa1b7 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -14,12 +14,86 @@ ******************************************************************************/ #include "CCdice.h" -#include "../txmempool.h" /* -*/ + in order to implement a dice game, we need a source of entropy, reasonably fast completion time and a way to manage the utxos. + + 1. CC vout locks "house" funds with hash(entropy) + half of shared secret + 2. bettor submits bet, with entropy, odds, houseid and sends combined amount into another CC vout. + 3. house account sends funds to winner with proof of entropy + 4. if timeout, bettor wins funds + + 2. and 3. can be done in mempool + */ -// start of consensus code +uint64_t DiceCalc(uint64_t amount,uint256 txid,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit) +{ + uint64_t duration,reward = 0; + if ( (duration= CCduration(txid)) < minseconds ) + { + return(0); + //duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24); + } else if ( duration > maxseconds ) + maxseconds = duration; + reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100); + fprintf(stderr,"amount %.8f %.8f %llu -> duration.%llu reward %.8f\n",(double)amount/COIN,((double)amount * APR)/COIN,(long long)((amount * APR) / (COIN * 365*24*3600)),(long long)duration,(double)reward/COIN); + return(reward); +} + +CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit) +{ + CScript opret; uint8_t evalcode = EVAL_DICE; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << APR << minseconds << maxseconds << mindeposit); + return(opret); +} + +uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit) +{ + 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 >> sbits; ss >> APR; ss >> minseconds; ss >> maxseconds; ss >> mindeposit) != 0 ) + { + if ( e == EVAL_DICE && f == 'F' ) + return(f); + } + return(0); +} + +CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid) +{ + CScript opret; uint8_t evalcode = EVAL_DICE; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid); + return(opret); +} + +uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid) +{ + std::vector vopret; uint8_t *script,e,f,funcid; uint64_t APR,minseconds,maxseconds,mindeposit; + GetOpReturnData(scriptPubKey, vopret); + if ( vopret.size() > 2 ) + { + script = (uint8_t *)vopret.data(); + if ( script[0] == EVAL_DICE ) + { + if ( script[1] == 'F' ) + { + if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> APR; ss >> minseconds; ss >> maxseconds; ss >> mindeposit) != 0 ) + { + fundingtxid = txid; + return('F'); + } else fprintf(stderr,"unmarshal error for F\n"); + } + else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid) != 0 ) + { + if ( e == EVAL_DICE && (f == 'L' || f == 'U' || f == 'A') ) + return(f); + else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f); + } + } else fprintf(stderr,"script[0] %02x != EVAL_DICE\n",script[0]); + } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size()); + return(0); +} uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) { @@ -32,23 +106,20 @@ uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) return(0); } -bool DiceExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) +bool DiceExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee) { static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis; + CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis; numvins = tx.vin.size(); numvouts = tx.vout.size(); for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) { - //fprintf(stderr,"vini.%d check mempool\n",i); if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("cant find vinTx"); + return eval->Invalid("always should find vin, but didnt"); else { - //fprintf(stderr,"vini.%d check hash and vout\n",i); if ( hashBlock == zerohash ) return eval->Invalid("cant dice from mempool"); if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) @@ -62,17 +133,17 @@ bool DiceExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction & if ( (assetoshis= IsDicevout(cp,tx,i)) != 0 ) outputs += assetoshis; } - if ( inputs != outputs+COIN+txfee ) + if ( inputs != outputs+txfee ) { fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); - return eval->Invalid("mismatched inputs != outputs + COIN + txfee"); + return eval->Invalid("mismatched inputs != outputs + txfee"); } else return(true); } bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) { - int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; bool retval; + uint256 txid,fundingtxid,hashBlock; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx; numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; @@ -80,104 +151,361 @@ bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) return eval->Invalid("no vouts"); else { - //fprintf(stderr,"check vins\n"); - for (i=0; iGetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 ) + return eval->Invalid("cant find fundingtxid"); + else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) != 'F' ) + return eval->Invalid("fundingTx not valid"); + switch ( funcid ) { - fprintf(stderr,"diceget invalid vini\n"); - return eval->Invalid("illegal normal vini"); + case 'F': + //vins.*: normal inputs + //vout.0: CC vout for funding + //vout.1: normal marker vout for easy searching + //vout.2: normal change + //vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit + return eval->Invalid("unexpected DiceValidate for createfunding"); + break; + case 'A': + //vins.*: normal inputs + //vout.0: CC vout for funding + //vout.1: normal change + //vout.n-1: opreturn 'A' sbits fundingtxid + return eval->Invalid("unexpected DiceValidate for addfunding"); + break; + case 'L': + //vins.*: normal inputs + //vout.0: CC vout for locked funds + //vout.1: normal output to unlock address + //vout.2: change + //vout.n-1: opreturn 'L' sbits fundingtxid + return eval->Invalid("unexpected DiceValidate for lock"); + break; + case 'U': + //vin.0: locked funds CC vout.0 from lock + //vin.1+: funding CC vout.0 from 'F' and 'A' and 'U' + //vout.0: funding CC change + //vout.1: normal output to unlock address + //vout.n-1: opreturn 'U' sbits fundingtxid + for (i=0; iismyvin)(tx.vin[i].scriptSig) == 0 ) + return eval->Invalid("unexpected normal vin for unlock"); + } + if ( DiceExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue) == 0 ) + return false; + else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("always should find vin.0, but didnt"); + else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("lock tx vout.0 is normal output"); + else if ( tx.vout.size() < 3 ) + return eval->Invalid("unlock tx not enough vouts"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("unlock tx vout.0 is normal output"); + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) + return eval->Invalid("unlock tx vout.1 is CC output"); + else if ( tx.vout[1].scriptPubKey != vinTx.vout[1].scriptPubKey ) + return eval->Invalid("unlock tx vout.1 mismatched scriptPubKey"); + amount = vinTx.vout[0].nValue; + reward = DiceCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit); + if ( tx.vout[1].nValue > amount+reward ) + return eval->Invalid("unlock tx vout.1 isnt amount+reward"); + preventCCvouts = 1; + break; } } - //fprintf(stderr,"check amounts\n"); - if ( DiceExactAmounts(cp,eval,tx,1,10000) == false ) - { - fprintf(stderr,"diceget invalid amount\n"); - return false; - } - else - { - preventCCvouts = 1; - if ( IsDicevout(cp,tx,0) != 0 ) - { - preventCCvouts++; - i = 1; - } else i = 0; - if ( tx.vout[i].nValue != COIN ) - return eval->Invalid("invalid dice output"); - retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); - if ( retval != 0 ) - fprintf(stderr,"diceget validated\n"); - else fprintf(stderr,"diceget invalid\n"); - return(retval); - } + return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); } + return(true); } -// end of consensus code -// helper functions for rpc calls in rpcwallet.cpp - -uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs) +// 'L' vs 'F' and 'A' +uint64_t AddDiceInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs) { - char coinaddr[64]; uint64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t n = 0; + char coinaddr[64],str[65]; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; - // prevent dup - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + vout = (int32_t)it->first.index; + fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); + for (j=0; j 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( (nValue= IsDicevout(cp,vintx,(int32_t)it->first.index)) > 0 ) + if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 ) { + fprintf(stderr,"fundsflag.%d (%c) %.8f %.8f\n",fundsflag,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN); + if ( fundsflag != 0 && funcid != 'F' && funcid != 'A' && funcid != 'U' ) + continue; + else if ( fundsflag == 0 && (funcid != 'L' || tx.vout.size() < 4) ) + continue; if ( total != 0 && maxinputs != 0 ) - mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript())); - nValue = it->second.satoshis; - totalinputs += nValue; + { + if ( fundsflag == 0 ) + scriptPubKey = tx.vout[1].scriptPubKey; + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + } + totalinputs += it->second.satoshis; n++; if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) break; - } + } else fprintf(stderr,"null funcid\n"); } } return(totalinputs); } -std::string DiceBet(uint64_t txfee,uint64_t amount,uint64_t odds) +uint64_t DicePlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid) { - CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_DICE); - if ( txfee == 0 ) - txfee = 10000; - dicepk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddDiceInputs(cp,mtx,dicepk,nValue+txfee,60)) > 0 ) + char coinaddr[64]; uint64_t sbits,APR,minseconds,maxseconds,mindeposit,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; uint8_t funcid; + std::vector > unspentOutputs; + GetCCaddress(cp,coinaddr,pk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - if ( inputs > nValue ) - CCchange = (inputs - nValue - txfee); - if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_DICE,CCchange,dicepk)); - mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret)); - } else fprintf(stderr,"cant find dice inputs\n"); - return(0); -} - -std::string DiceFund(uint64_t txfee,uint64_t funds) -{ - CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_DICE); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - dicepk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_DICE,funds,dicepk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); + txid = it->first.txhash; + vout = (int32_t)it->first.index; + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 ) + { + if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid ) + { + if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 0 ) + totalinputs += nValue; + else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN); + } else fprintf(stderr,"else case\n"); + } else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN); + } } + return(totalinputs); +} + +bool DicePlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,uint64_t &APR,uint64_t &minseconds,uint64_t &maxseconds,uint64_t &mindeposit) +{ + char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx; + std::vector > txids; + GetCCaddress(cp,CCaddr,dicepk); + SetCCtxids(txids,CCaddr); + for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) + { + //int height = it->first.blockHeight; + txid = it->first.txhash; + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 ) + { + if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 'F' ) + { + if ( sbits == refsbits ) + return(true); + } + } + } + return(false); +} + +UniValue DiceInfo(uint256 diceid) +{ + UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; uint64_t APR,minseconds,maxseconds,mindeposit,sbits; char str[67],numstr[65]; + if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 ) + { + fprintf(stderr,"cant find fundingtxid\n"); + result.push_back(Pair("error","cant find fundingtxid")); + return(result); + } + if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) == 0 ) + { + fprintf(stderr,"fundingtxid isnt dice creation txid\n"); + result.push_back(Pair("error","fundingtxid isnt dice creation txid")); + return(result); + } + result.push_back(Pair("result","success")); + result.push_back(Pair("fundingtxid",uint256_str(str,diceid))); + unstringbits(str,sbits); + result.push_back(Pair("name",str)); + result.push_back(Pair("sbits",sbits)); + sprintf(numstr,"%.8f",(double)APR/COIN); + result.push_back(Pair("APR",numstr)); + result.push_back(Pair("minseconds",minseconds)); + result.push_back(Pair("maxseconds",maxseconds)); + sprintf(numstr,"%.8f",(double)mindeposit/COIN); + result.push_back(Pair("mindeposit",numstr)); + sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN); + result.push_back(Pair("funding",numstr)); + return(result); +} + +UniValue DiceList() +{ + UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits,APR,minseconds,maxseconds,mindeposit; char str[65]; + cp = CCinit(&C,EVAL_DICE); + SetCCtxids(addressIndex,cp->normaladdr); + for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) + { + txid = it->first.txhash; + if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + { + if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,APR,minseconds,maxseconds,mindeposit) != 0 ) + { + result.push_back(uint256_str(str,txid)); + } + } + } + return(result); +} + +std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t APR,int64_t minseconds,int64_t maxseconds,int64_t mindeposit) +{ + CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C; + if ( funds < 0 || mindeposit < 0 || minseconds < 0 || maxseconds < 0 ) + { + fprintf(stderr,"negative parameter error\n"); + return(0); + } + cp = CCinit(&C,EVAL_DICE); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + dicepk = GetUnspendable(cp,0); + sbits = stringbits(planstr); + if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) != 0 ) + { + fprintf(stderr,"Dice plan (%s) already exists\n",planstr); + return(0); + } + if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,APR,minseconds,maxseconds,mindeposit))); + } + fprintf(stderr,"cant find enough inputs\n"); return(0); } +std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount) +{ + CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits,a,b,c,d; struct CCcontract_info *cp,C; + if ( amount < 0 ) + { + fprintf(stderr,"negative parameter error\n"); + return(0); + } + cp = CCinit(&C,EVAL_DICE); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + dicepk = GetUnspendable(cp,0); + sbits = stringbits(planstr); + if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) == 0 ) + { + fprintf(stderr,"Dice plan %s doesnt exist\n",planstr); + return(0); + } + sbits = stringbits(planstr); + if ( AddNormalinputs(mtx,mypk,amount+txfee,64) > 0 ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('A',sbits,fundingtxid))); + } else fprintf(stderr,"cant find enough inputs\n"); + fprintf(stderr,"cant find fundingtxid\n"); + return(0); +} + +std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t wager,int32_t odds) +{ + CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits,funding,APR,minseconds,maxseconds,minwager; struct CCcontract_info *cp,C; + if ( wager < 0 ) + { + fprintf(stderr,"negative parameter error\n"); + return(0); + } + cp = CCinit(&C,EVAL_DICE); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + dicepk = GetUnspendable(cp,0); + sbits = stringbits(planstr); + if ( DicePlanExists(cp,sbits,dicepk,APR,minseconds,maxseconds,minwager) == 0 ) + { + fprintf(stderr,"Dice plan %s doesnt exist\n",planstr); + return(0); + } + if ( wager < minwager ) + { + fprintf(stderr,"Dice plan %s wager %.8f < minwager %.8f\n",planstr,(double)wager/COIN,(double)minwager/COIN); + return(0); + } + if ( (funding= DicePlanFunds(sbits,cp,dicepk,fundingtxid)) >= wager ) // arbitrary cmpval + { + if ( AddNormalinputs(mtx,mypk,wager+2*txfee,64) > 0 ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,wager,dicepk)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('L',sbits,fundingtxid))); + } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)wager/COIN); + } + fprintf(stderr,"cant find dice inputs\n"); + return(0); +} + +std::string DiceUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid) +{ + CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,dicepk; CScript opret,scriptPubKey,ignore; uint256 hashBlock; uint64_t funding,sbits,reward=0,amount=0,inputs,CCchange=0,APR,minseconds,maxseconds,mindeposit; struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_DICE); + if ( txfee == 0 ) + txfee = 10000; + dicepk = GetUnspendable(cp,0); + mypk = pubkey2pk(Mypubkey()); + sbits = stringbits(planstr); + if ( DicePlanExists(cp,sbits,dicepk,APR,minseconds,maxseconds,mindeposit) == 0 ) + { + fprintf(stderr,"Dice plan %s doesnt exist\n",planstr); + return(0); + } + // need to deal with finding the right utxos + if ( locktxid == zeroid ) + amount = AddDiceInputs(scriptPubKey,0,cp,mtx,dicepk,(1LL << 30),1); + else + { + GetCCaddress(cp,coinaddr,dicepk); + if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 ) + { + fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr); + return(0); + } + if ( GetTransaction(locktxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + { + scriptPubKey = tx.vout[1].scriptPubKey; + mtx.vin.push_back(CTxIn(locktxid,0,CScript())); + } + else + { + fprintf(stderr,"%s no normal vout.1 in locktxid\n",coinaddr); + return(0); + } + } + if ( amount > 0 && (reward= DiceCalc(amount,mtx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit)) > txfee && scriptPubKey.size() > 0 ) + { + if ( (inputs= AddDiceInputs(ignore,1,cp,mtx,dicepk,reward+txfee,30)) > 0 ) + { + if ( inputs >= (reward + 2*txfee) ) + CCchange = (inputs - (reward + txfee)); + fprintf(stderr,"inputs %.8f CCchange %.8f amount %.8f reward %.8f\n",(double)inputs/COIN,(double)CCchange/COIN,(double)amount/COIN,(double)reward/COIN); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk)); + mtx.vout.push_back(CTxOut(amount+reward,scriptPubKey)); + return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,EncodeDiceOpRet('U',sbits,fundingtxid))); + } + fprintf(stderr,"cant find enough dice inputs\n"); + } + fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN); + return(0); +} diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 2944c1bee..b4fcf737e 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -69,12 +69,13 @@ uint64_t RewardsCalc(uint64_t amount,uint256 txid,uint64_t APR,uint64_t minseconds,uint64_t maxseconds,uint64_t mindeposit) { uint64_t duration,reward = 0; + fprintf(stderr,"minseconds %llu maxseconds %llu\n",(long long)minseconds,(long long)maxseconds); if ( (duration= CCduration(txid)) < minseconds ) { return(0); //duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24); } else if ( duration > maxseconds ) - maxseconds = duration; + duration = maxseconds; reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100); fprintf(stderr,"amount %.8f %.8f %llu -> duration.%llu reward %.8f\n",(double)amount/COIN,((double)amount * APR)/COIN,(long long)((amount * APR) / (COIN * 365*24*3600)),(long long)duration,(double)reward/COIN); return(reward);