]> Git Repo - VerusCoin.git/blame - src/cc/dice.cpp
;
[VerusCoin.git] / src / cc / dice.cpp
CommitLineData
cfea7a46 1/******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
3 * *
4 * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
5 * the top-level directory of this distribution for the individual copyright *
6 * holder information and the developer policies on copyright and licensing. *
7 * *
8 * Unless otherwise agreed in a custom licensing agreement, no part of the *
9 * SuperNET software, including this file may be copied, modified, propagated *
10 * or distributed except according to the terms contained in the LICENSE file *
11 * *
12 * Removal or modification of this copyright notice is prohibited. *
13 * *
14 ******************************************************************************/
15
16#include "CCdice.h"
cfea7a46 17
18/*
10078e85 19 in order to implement a dice game, we need a source of entropy, reasonably fast completion time and a way to manage the utxos.
20
21 1. CC vout locks "house" funds with hash(entropy) + half of shared secret
22 2. bettor submits bet, with entropy, odds, houseid and sends combined amount into another CC vout.
23 3. house account sends funds to winner with proof of entropy
24 4. if timeout, bettor wins funds
25
26 2. and 3. can be done in mempool
27 */
cfea7a46 28
ae748eaf 29#include "../endian.h"
30
31void endiancpy(uint8_t *dest,uint8_t *src,int32_t len)
32{
33 int32_t i,j=0;
34#if defined(WORDS_BIGENDIAN)
35 for (i=31; i>=0; i--)
36 dest[j++] = src[i];
37#else
17bc6201 38 memcpy(dest,src,len);
ae748eaf 39#endif
40}
41
dfe4c146 42uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv) // max 1 vout per txid used
8138fad2 43{
ae748eaf 44 int32_t i; uint8_t _entropy[32],_hentropy[32]; bits256 tmp256,txidpub,txidpriv,mypriv,mypub,ssecret,ssecret2; uint256 hentropy;
72362bbe 45 memset(&hentropy,0,32);
e0e655fe 46 endiancpy(txidpriv.bytes,(uint8_t *)&_txidpriv,32);
d176d2df 47 txidpriv.bytes[0] &= 0xf8, txidpriv.bytes[31] &= 0x7f, txidpriv.bytes[31] |= 0x40;
48 txidpub = curve25519(txidpriv,curve25519_basepoint9());
49
50 Myprivkey(tmp256.bytes);
51 vcalc_sha256(0,mypriv.bytes,tmp256.bytes,32);
52 mypriv.bytes[0] &= 0xf8, mypriv.bytes[31] &= 0x7f, mypriv.bytes[31] |= 0x40;
53 mypub = curve25519(mypriv,curve25519_basepoint9());
54
91f21771 55 ssecret = curve25519(mypriv,txidpub);
56 ssecret2 = curve25519(txidpriv,mypub);
d176d2df 57 if ( memcmp(ssecret.bytes,ssecret2.bytes,32) == 0 )
8138fad2 58 {
ae748eaf 59 vcalc_sha256(0,(uint8_t *)&_entropy,ssecret.bytes,32);
60 vcalc_sha256(0,(uint8_t *)&_hentropy,_entropy,32);
dfe4c146 61 endiancpy((uint8_t *)&entropy,_entropy,32);
62 endiancpy((uint8_t *)&hentropy,_hentropy,32);
840a96ca 63 }
64 else
65 {
66 for (i=0; i<32; i++)
774b8b44 67 fprintf(stderr,"%02x",ssecret.bytes[i]);
840a96ca 68 fprintf(stderr," ssecret\n");
69 for (i=0; i<32; i++)
ac9816bb 70 fprintf(stderr,"%02x",ssecret2.bytes[i]);
840a96ca 71 fprintf(stderr," ssecret2 dont match\n");
72 }
8138fad2 73 return(hentropy);
74}
75
d0d96ab0 76uint64_t DiceCalc(uint64_t amount,uint256 txid,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
10078e85 77{
d0d96ab0 78 /*uint64_t duration,reward = 0;
10078e85 79 if ( (duration= CCduration(txid)) < minseconds )
80 {
81 return(0);
82 //duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24);
83 } else if ( duration > maxseconds )
84 maxseconds = duration;
85 reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100);
86 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);
d0d96ab0 87 return(reward);*/
88 return(0);
10078e85 89}
90
d0d96ab0 91CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
10078e85 92{
93 CScript opret; uint8_t evalcode = EVAL_DICE;
d0d96ab0 94 opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << forfeitblocks);
10078e85 95 return(opret);
96}
97
d0d96ab0 98uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &forfeitblocks)
10078e85 99{
100 std::vector<uint8_t> vopret; uint8_t *script,e,f;
101 GetOpReturnData(scriptPubKey, vopret);
102 script = (uint8_t *)vopret.data();
d0d96ab0 103 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 0 )
10078e85 104 {
105 if ( e == EVAL_DICE && f == 'F' )
106 return(f);
107 }
108 return(0);
109}
110
8138fad2 111CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid,uint256 hash)
10078e85 112{
113 CScript opret; uint8_t evalcode = EVAL_DICE;
8138fad2 114 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid << hash);
10078e85 115 return(opret);
116}
117
8138fad2 118uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid,uint256 &hash)
10078e85 119{
d0d96ab0 120 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,forfeitblocks;
10078e85 121 GetOpReturnData(scriptPubKey, vopret);
122 if ( vopret.size() > 2 )
123 {
124 script = (uint8_t *)vopret.data();
125 if ( script[0] == EVAL_DICE )
126 {
127 if ( script[1] == 'F' )
128 {
d0d96ab0 129 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 0 )
10078e85 130 {
72362bbe 131 memset(&hash,0,32);
10078e85 132 fundingtxid = txid;
133 return('F');
134 } else fprintf(stderr,"unmarshal error for F\n");
135 }
8138fad2 136 else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid; ss >> hash) != 0 )
10078e85 137 {
28b947b8 138 if ( e == EVAL_DICE && (f == 'B' || f == 'U' || f == 'E') )
10078e85 139 return(f);
140 else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f);
141 }
142 } else fprintf(stderr,"script[0] %02x != EVAL_DICE\n",script[0]);
143 } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
144 return(0);
145}
cfea7a46 146
147uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
148{
149 char destaddr[64];
150 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
151 {
152 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
153 return(tx.vout[v].nValue);
154 }
155 return(0);
156}
157
10078e85 158bool DiceExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee)
cfea7a46 159{
160 static uint256 zerohash;
10078e85 161 CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis;
cfea7a46 162 numvins = tx.vin.size();
163 numvouts = tx.vout.size();
164 for (i=0; i<numvins; i++)
165 {
cfea7a46 166 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
167 {
cfea7a46 168 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
10078e85 169 return eval->Invalid("always should find vin, but didnt");
cfea7a46 170 else
171 {
cfea7a46 172 if ( hashBlock == zerohash )
173 return eval->Invalid("cant dice from mempool");
174 if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
175 inputs += assetoshis;
176 }
177 }
178 }
179 for (i=0; i<numvouts; i++)
180 {
181 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
182 if ( (assetoshis= IsDicevout(cp,tx,i)) != 0 )
183 outputs += assetoshis;
184 }
10078e85 185 if ( inputs != outputs+txfee )
cfea7a46 186 {
187 fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
10078e85 188 return eval->Invalid("mismatched inputs != outputs + txfee");
cfea7a46 189 }
190 else return(true);
191}
192
1c87477b 193bool DiceIsmine(const CScript scriptPubKey)
194{
195 char destaddr[64],myaddr[64];
196 Getscriptaddress(destaddr,scriptPubKey);
ca05cbaa 197 Getscriptaddress(myaddr,CScript() << Mypubkey() << OP_CHECKSIG);
1c87477b 198 return(strcmp(destaddr,myaddr) == 0);
199}
200
cfea7a46 201bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
202{
72362bbe 203 uint256 txid,fundingtxid,hashBlock,hash; int64_t minbet,maxbet,maxodds,forfeitblocks; uint64_t sbits,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
cfea7a46 204 numvins = tx.vin.size();
205 numvouts = tx.vout.size();
206 preventCCvins = preventCCvouts = -1;
207 if ( numvouts < 1 )
208 return eval->Invalid("no vouts");
209 else
210 {
10078e85 211 txid = tx.GetHash();
72362bbe 212 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash)) != 0 )
cfea7a46 213 {
10078e85 214 if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
215 return eval->Invalid("cant find fundingtxid");
d0d96ab0 216 else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 'F' )
10078e85 217 return eval->Invalid("fundingTx not valid");
218 switch ( funcid )
cfea7a46 219 {
10078e85 220 case 'F':
221 //vins.*: normal inputs
222 //vout.0: CC vout for funding
223 //vout.1: normal marker vout for easy searching
224 //vout.2: normal change
225 //vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit
226 return eval->Invalid("unexpected DiceValidate for createfunding");
227 break;
28b947b8 228 case 'E':
10078e85 229 //vins.*: normal inputs
0d4cfd0b 230 //vout.0: CC vout for locked entropy funds
231 //vout.1: tag to owner address for entropy funds
232 //vout.2: normal change
28b947b8 233 //vout.n-1: opreturn 'E' sbits fundingtxid hentropy
234 return eval->Invalid("unexpected DiceValidate for addfunding entropy");
10078e85 235 break;
04cf9f60 236 case 'B':
28b947b8 237 //vin.0: entropy txid from house
238 //vins.1+: normal inputs
0d4cfd0b 239 //vout.0: CC vout for locked entropy
28b947b8 240 //vout.1: CC vout for locked bet
241 //vout.2: tag for bettor's address
242 //vout.3: change
243 //vout.n-1: opreturn 'B' sbits fundingtxid entropy
244 // get house hentropy and its vin0.prevtxid, cmp vout1 to owner address
245 // if owneraddress is me, then validate hentropy and submit outcome tx
246 fprintf(stderr,"got bet txid\n");
1c87477b 247 if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
248 return eval->Invalid("always should find vin.0, but didnt");
249 else if ( DiceIsmine(vinTx.vout[1].scriptPubKey) != 0 )
250 {
251 fprintf(stderr,"I am house entropy %.8f\n",(double)vinTx.vout[0].nValue/COIN);
252
253 }
28b947b8 254 return eval->Invalid("dont confirm bet during debug");
10078e85 255 break;
256 case 'U':
257 //vin.0: locked funds CC vout.0 from lock
28b947b8 258 //vin.1+: funding CC vout.0 from 'F' and 'E' and 'U'
10078e85 259 //vout.0: funding CC change
260 //vout.1: normal output to unlock address
261 //vout.n-1: opreturn 'U' sbits fundingtxid
262 for (i=0; i<numvins; i++)
263 {
264 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
265 return eval->Invalid("unexpected normal vin for unlock");
266 }
267 if ( DiceExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue) == 0 )
268 return false;
269 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
270 return eval->Invalid("always should find vin.0, but didnt");
271 else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
272 return eval->Invalid("lock tx vout.0 is normal output");
273 else if ( tx.vout.size() < 3 )
274 return eval->Invalid("unlock tx not enough vouts");
275 else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
276 return eval->Invalid("unlock tx vout.0 is normal output");
277 else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
278 return eval->Invalid("unlock tx vout.1 is CC output");
279 else if ( tx.vout[1].scriptPubKey != vinTx.vout[1].scriptPubKey )
280 return eval->Invalid("unlock tx vout.1 mismatched scriptPubKey");
281 amount = vinTx.vout[0].nValue;
d0d96ab0 282 reward = DiceCalc(amount,tx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks);
10078e85 283 if ( tx.vout[1].nValue > amount+reward )
284 return eval->Invalid("unlock tx vout.1 isnt amount+reward");
285 preventCCvouts = 1;
286 break;
cfea7a46 287 }
288 }
10078e85 289 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
cfea7a46 290 }
10078e85 291 return(true);
cfea7a46 292}
cfea7a46 293
28b947b8 294// 'B' vs 'F' and 'E'
10078e85 295uint64_t AddDiceInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
cfea7a46 296{
72362bbe 297 char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hash,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
cfea7a46 298 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
299 GetCCaddress(cp,coinaddr,pk);
300 SetCCunspents(unspentOutputs,coinaddr);
301 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
302 {
303 txid = it->first.txhash;
10078e85 304 vout = (int32_t)it->first.index;
305 fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
306 for (j=0; j<mtx.vin.size(); j++)
307 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
308 break;
309 if ( j != mtx.vin.size() )
310 continue;
311 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
cfea7a46 312 {
72362bbe 313 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash)) != 0 )
cfea7a46 314 {
10078e85 315 fprintf(stderr,"fundsflag.%d (%c) %.8f %.8f\n",fundsflag,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
28b947b8 316 if ( fundsflag != 0 && funcid != 'F' && funcid != 'E' && funcid != 'U' )
10078e85 317 continue;
04cf9f60 318 else if ( fundsflag == 0 && (funcid != 'B' || tx.vout.size() < 4) )
10078e85 319 continue;
cfea7a46 320 if ( total != 0 && maxinputs != 0 )
10078e85 321 {
322 if ( fundsflag == 0 )
323 scriptPubKey = tx.vout[1].scriptPubKey;
324 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
325 }
326 totalinputs += it->second.satoshis;
cfea7a46 327 n++;
328 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
329 break;
10078e85 330 } else fprintf(stderr,"null funcid\n");
cfea7a46 331 }
332 }
333 return(totalinputs);
334}
335
04cf9f60 336uint64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
10078e85 337{
04cf9f60 338 char coinaddr[64]; uint64_t sbits,nValue,totalinputs = 0; uint256 hash,txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout,first=0; uint8_t funcid;
10078e85 339 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
340 GetCCaddress(cp,coinaddr,pk);
341 SetCCunspents(unspentOutputs,coinaddr);
04cf9f60 342 entropyval = 0;
10078e85 343 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
344 {
345 txid = it->first.txhash;
346 vout = (int32_t)it->first.index;
347 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
348 {
72362bbe 349 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash)) != 0 )
10078e85 350 {
351 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
352 {
353 if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 0 )
04cf9f60 354 {
10078e85 355 totalinputs += nValue;
35d43add 356 fprintf(stderr,"add %.8f\n",(double)nValue/COIN);
28b947b8 357 if ( first == 0 && funcid == 'E' )
04cf9f60 358 {
359 entropytxid = txid;
360 entropyval = tx.vout[0].nValue;
361 first = 1;
362 }
363 }
10078e85 364 else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN);
35d43add 365 } else fprintf(stderr,"else case funcid %d\n",funcid);
10078e85 366 } else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
367 }
368 }
369 return(totalinputs);
370}
371
d0d96ab0 372bool DicePlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &forfeitblocks)
10078e85 373{
374 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
375 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
376 GetCCaddress(cp,CCaddr,dicepk);
377 SetCCtxids(txids,CCaddr);
378 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
379 {
380 //int height = it->first.blockHeight;
381 txid = it->first.txhash;
382 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
383 {
d0d96ab0 384 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 'F' )
10078e85 385 {
386 if ( sbits == refsbits )
387 return(true);
388 }
389 }
390 }
391 return(false);
392}
393
394UniValue DiceInfo(uint256 diceid)
395{
d0d96ab0 396 UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; int64_t minbet,maxbet,maxodds,forfeitblocks; uint64_t sbits; char str[67],numstr[65];
10078e85 397 if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 )
398 {
399 fprintf(stderr,"cant find fundingtxid\n");
400 result.push_back(Pair("error","cant find fundingtxid"));
401 return(result);
402 }
d0d96ab0 403 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 0 )
10078e85 404 {
405 fprintf(stderr,"fundingtxid isnt dice creation txid\n");
406 result.push_back(Pair("error","fundingtxid isnt dice creation txid"));
407 return(result);
408 }
409 result.push_back(Pair("result","success"));
410 result.push_back(Pair("fundingtxid",uint256_str(str,diceid)));
411 unstringbits(str,sbits);
412 result.push_back(Pair("name",str));
413 result.push_back(Pair("sbits",sbits));
d0d96ab0 414 sprintf(numstr,"%.8f",(double)minbet/COIN);
415 result.push_back(Pair("minbet",numstr));
416 sprintf(numstr,"%.8f",(double)maxbet/COIN);
417 result.push_back(Pair("maxbet",numstr));
418 result.push_back(Pair("maxodds",maxodds));
419 result.push_back(Pair("forfeitblocks",forfeitblocks));
10078e85 420 sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
421 result.push_back(Pair("funding",numstr));
422 return(result);
423}
424
425UniValue DiceList()
cfea7a46 426{
d0d96ab0 427 UniValue result(UniValue::VARR); std::vector<std::pair<CAddressIndexKey, CAmount> > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits; int64_t minbet,maxbet,maxodds,forfeitblocks; char str[65];
10078e85 428 cp = CCinit(&C,EVAL_DICE);
429 SetCCtxids(addressIndex,cp->normaladdr);
430 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
431 {
432 txid = it->first.txhash;
433 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
434 {
d0d96ab0 435 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 0 )
10078e85 436 {
437 result.push_back(uint256_str(str,txid));
438 }
439 }
440 }
441 return(result);
442}
443
d0d96ab0 444std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
10078e85 445{
d0d96ab0 446 CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C;
0e84bf92 447 if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || forfeitblocks < 0 || forfeitblocks > 1440 )
10078e85 448 {
449 fprintf(stderr,"negative parameter error\n");
450 return(0);
451 }
cfea7a46 452 cp = CCinit(&C,EVAL_DICE);
453 if ( txfee == 0 )
454 txfee = 10000;
10078e85 455 mypk = pubkey2pk(Mypubkey());
cfea7a46 456 dicepk = GetUnspendable(cp,0);
10078e85 457 sbits = stringbits(planstr);
458 if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) != 0 )
459 {
460 fprintf(stderr,"Dice plan (%s) already exists\n",planstr);
461 return(0);
462 }
463 if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 )
464 {
465 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk));
466 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG));
d0d96ab0 467 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,forfeitblocks)));
10078e85 468 }
469 fprintf(stderr,"cant find enough inputs\n");
470 return(0);
471}
472
473std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
474{
8138fad2 475 CMutableTransaction mtx; uint256 entropy,hentropy; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C;
10078e85 476 if ( amount < 0 )
477 {
478 fprintf(stderr,"negative parameter error\n");
479 return(0);
480 }
481 cp = CCinit(&C,EVAL_DICE);
482 if ( txfee == 0 )
483 txfee = 10000;
cfea7a46 484 mypk = pubkey2pk(Mypubkey());
10078e85 485 dicepk = GetUnspendable(cp,0);
486 sbits = stringbits(planstr);
487 if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) == 0 )
488 {
489 fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
490 return(0);
491 }
492 sbits = stringbits(planstr);
0d4cfd0b 493 if ( AddNormalinputs(mtx,mypk,amount+2*txfee,64) > 0 )
10078e85 494 {
8138fad2 495 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
10078e85 496 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk));
0d4cfd0b 497 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
28b947b8 498 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('E',sbits,fundingtxid,hentropy)));
10078e85 499 } else fprintf(stderr,"cant find enough inputs\n");
500 fprintf(stderr,"cant find fundingtxid\n");
cfea7a46 501 return(0);
502}
503
d0d96ab0 504std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds)
cfea7a46 505{
04cf9f60 506 CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits,entropyval; int64_t funding,minbet,maxbet,maxodds,forfeitblocks; uint256 entropytxid,entropy,hentropy; struct CCcontract_info *cp,C;
c857567a 507 if ( bet < 0 || odds < 1 )
10078e85 508 {
509 fprintf(stderr,"negative parameter error\n");
510 return(0);
511 }
cfea7a46 512 cp = CCinit(&C,EVAL_DICE);
513 if ( txfee == 0 )
514 txfee = 10000;
515 mypk = pubkey2pk(Mypubkey());
516 dicepk = GetUnspendable(cp,0);
10078e85 517 sbits = stringbits(planstr);
d0d96ab0 518 if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 )
cfea7a46 519 {
10078e85 520 fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
521 return(0);
522 }
d0d96ab0 523 if ( bet < minbet )
10078e85 524 {
d0d96ab0 525 fprintf(stderr,"Dice plan %s bet %.8f < minbet %.8f\n",planstr,(double)bet/COIN,(double)minbet/COIN);
10078e85 526 return(0);
527 }
04cf9f60 528 if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid)) >= bet*odds+txfee && entropyval != 0 )
10078e85 529 {
0d4cfd0b 530 mtx.vin.push_back(CTxIn(entropytxid,0,CScript()));
1c87477b 531 if ( AddNormalinputs(mtx,mypk,bet+2*txfee,60) > 0 )
10078e85 532 {
8138fad2 533 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
04cf9f60 534 mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk));
3f9f8229 535 mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk));
10078e85 536 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
28b947b8 537 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('B',sbits,fundingtxid,entropy)));
3f9f8229 538 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN);
cfea7a46 539 }
04cf9f60 540 if ( entropyval == 0 && funding != 0 )
541 fprintf(stderr,"cant find dice entropy inputs\n");
542 else fprintf(stderr,"cant find dice inputs\n");
cfea7a46 543 return(0);
544}
545
10078e85 546std::string DiceUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
547{
5db44aff 548 int32_t houseflag = 1;
8138fad2 549 CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,dicepk; CScript opret,scriptPubKey,ignore; uint256 hashBlock,entropy,hentropy; uint64_t funding,sbits,reward=0,amount=0,inputs,CCchange=0; int64_t minbet,maxbet,maxodds,forfeitblocks; struct CCcontract_info *cp,C;
10078e85 550 cp = CCinit(&C,EVAL_DICE);
551 if ( txfee == 0 )
552 txfee = 10000;
553 dicepk = GetUnspendable(cp,0);
554 mypk = pubkey2pk(Mypubkey());
555 sbits = stringbits(planstr);
d0d96ab0 556 if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 )
10078e85 557 {
558 fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
559 return(0);
560 }
561 // need to deal with finding the right utxos
562 if ( locktxid == zeroid )
563 amount = AddDiceInputs(scriptPubKey,0,cp,mtx,dicepk,(1LL << 30),1);
564 else
565 {
566 GetCCaddress(cp,coinaddr,dicepk);
567 if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
568 {
569 fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
570 return(0);
571 }
572 if ( GetTransaction(locktxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
573 {
574 scriptPubKey = tx.vout[1].scriptPubKey;
575 mtx.vin.push_back(CTxIn(locktxid,0,CScript()));
576 }
577 else
578 {
579 fprintf(stderr,"%s no normal vout.1 in locktxid\n",coinaddr);
580 return(0);
581 }
582 }
d0d96ab0 583 if ( amount > 0 && (reward= DiceCalc(amount,mtx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks)) > txfee && scriptPubKey.size() > 0 )
10078e85 584 {
585 if ( (inputs= AddDiceInputs(ignore,1,cp,mtx,dicepk,reward+txfee,30)) > 0 )
586 {
587 if ( inputs >= (reward + 2*txfee) )
588 CCchange = (inputs - (reward + txfee));
589 fprintf(stderr,"inputs %.8f CCchange %.8f amount %.8f reward %.8f\n",(double)inputs/COIN,(double)CCchange/COIN,(double)amount/COIN,(double)reward/COIN);
8138fad2 590 if ( houseflag != 0 )
591 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
592 else hentropy = zeroid;
10078e85 593 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk));
594 mtx.vout.push_back(CTxOut(amount+reward,scriptPubKey));
8138fad2 595 return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,EncodeDiceOpRet('U',sbits,fundingtxid,hentropy)));
10078e85 596 }
597 fprintf(stderr,"cant find enough dice inputs\n");
598 }
599 fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
600 return(0);
601}
cfea7a46 602
This page took 0.129172 seconds and 4 git commands to generate.