This commit is contained in:
jl777
2018-07-29 03:54:39 -11:00
parent 15185682b2
commit 10078e85a9
2 changed files with 411 additions and 82 deletions

View File

@@ -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<uint8_t> 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<uint8_t> 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; i<numvins; i++)
{
//fprintf(stderr,"vini.%d\n",i);
if ( (*cp->ismyvin)(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; i<numvins; i++)
txid = tx.GetHash();
if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
{
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
if ( eval->GetTxUnconfirmed(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; i<numvins; i++)
{
if ( (*cp->ismyvin)(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<uint8_t> 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<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::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<mtx.vin.size(); j++)
if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
break;
if ( j != mtx.vin.size() )
continue;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 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<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::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<std::pair<CAddressIndexKey, CAmount> > txids;
GetCCaddress(cp,CCaddr,dicepk);
SetCCtxids(txids,CCaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::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<std::pair<CAddressIndexKey, CAmount> > 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<std::pair<CAddressIndexKey, CAmount> >::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);
}