1 /******************************************************************************
2 * Copyright © 2014-2018 The SuperNET Developers. *
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. *
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 *
12 * Removal or modification of this copyright notice is prohibited. *
14 ******************************************************************************/
21 in order to implement a dice game, we need a source of entropy, reasonably fast completion time and a way to manage the utxos.
23 1. CC vout locks "house" funds with hash(entropy)
24 2. bettor submits bet, with entropy, odds, houseid and sends combined amount into another CC vout.
25 3. house account sends funds to winner/loser with proof of entropy
26 4. if timeout, bettor gets refund
28 2. and 3. can be done in mempool
30 The house commits to an entropy value by including the hash of the entropy value in the 'E' transaction.
32 To bet, one of these 'E' transactions is used as the first input and its hashed entropy is combined with the unhashed entropy attached to the bet 'B' transaction.
34 The house node monitors the 'B' transactions and if it sees one of its own, it creates either a winner 'W' or loser 'L' transaction, with proof of hash of entropy.
36 In the even the house node doesnt respond before timeoutblocks, then anybody (including bettor) can undo the bet with funds going back to the house and bettor
38 In order for people to play dice, someone (anyone) needs to create a funded dice plan and addfunding with enough utxo to allow players to find one.
42 vout.0: CC vout for funding
44 vout.2: dice marker address vout for easy searching
46 vout.n-1: opreturn 'F' sbits minbet maxbet maxodds timeoutblocks
50 vout.0: CC vout for locked entropy funds
51 vout.1: tag to owner address for entropy funds
53 vout.n-1: opreturn 'E' sbits fundingtxid hentropy
56 vin.0: entropy txid from house (must validate vin0 of 'E')
57 vins.1+: normal inputs
58 vout.0: CC vout for locked entropy
59 vout.1: CC vout for locked bet
60 vout.2: tag for bettor's address (txfee + odds)
62 vout.n-1: opreturn 'B' sbits fundingtxid entropy
66 vin.1: betTx CC vout.0 entropy from bet
67 vin.2: betTx CC vout.1 bet amount from bet
68 vin.3+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T'
69 vout.0: funding CC to entropy owner
70 vout.1: tag to owner address for entropy funds
71 vout.2: change to fundingpk
72 vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof
75 same as loser, but vout.2 is winnings
76 vout.3: change to fundingpk
77 vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
80 same as winner, just without hentropy or proof
84 #include "../endian.h"
86 static uint256 bettxids[128];
88 struct dicefinish_info
90 uint256 fundingtxid,bettxid;
95 bool mySendrawtransaction(std::string res)
97 CTransaction tx; char str[65];
98 if ( res.empty() == 0 && res.size() > 64 && is_hexstr((char *)res.c_str(),0) > 64 )
100 if ( DecodeHexTx(tx,res) != 0 )
102 fprintf(stderr,"%s\n%s\n",res.c_str(),uint256_str(str,tx.GetHash()));
104 if ( myAddtomempool(tx) != 0 )
106 RelayTransaction(tx);
107 fprintf(stderr,"added to mempool and broadcast\n");
109 } else fprintf(stderr,"error adding to mempool\n");
110 } else fprintf(stderr,"error decoding hex\n");
115 void *dicefinish(void *_ptr)
117 char str[65],str2[65],name[32]; std::string res; int32_t i,result,duplicate=0; struct dicefinish_info *ptr;
118 ptr = (struct dicefinish_info *)_ptr;
119 sleep(3); // wait for bettxid to be in mempool
120 for (i=0; i<sizeof(bettxids)/sizeof(*bettxids); i++)
121 if ( bettxids[i] == ptr->bettxid )
126 if ( duplicate == 0 )
128 for (i=0; i<sizeof(bettxids)/sizeof(*bettxids); i++)
129 if ( bettxids[i] == zeroid )
131 bettxids[i] = ptr->bettxid;
134 if ( i == sizeof(bettxids)/sizeof(*bettxids) )
135 bettxids[rand() % i] = ptr->bettxid;
137 unstringbits(name,ptr->sbits);
138 //fprintf(stderr,"duplicate.%d dicefinish.%d %s funding.%s bet.%s\n",duplicate,ptr->iswin,name,uint256_str(str,ptr->fundingtxid),uint256_str(str2,ptr->bettxid));
139 if ( duplicate == 0 )
141 res = DiceBetFinish(&result,0,name,ptr->fundingtxid,ptr->bettxid,ptr->iswin);
143 mySendrawtransaction(res);
149 void DiceQueue(int32_t iswin,uint64_t sbits,uint256 fundingtxid,uint256 bettxid)
151 struct dicefinish_info *ptr = (struct dicefinish_info *)calloc(1,sizeof(*ptr));
152 ptr->fundingtxid = fundingtxid;
153 ptr->bettxid = bettxid;
156 if ( ptr != 0 && pthread_create((pthread_t *)malloc(sizeof(pthread_t)),NULL,dicefinish,(void *)ptr) != 0 )
158 //fprintf(stderr,"DiceQueue.%d\n",iswin);
159 } // small memory leak per DiceQueue
162 void endiancpy(uint8_t *dest,uint8_t *src,int32_t len)
165 #if defined(WORDS_BIGENDIAN)
166 for (i=31; i>=0; i--)
169 memcpy(dest,src,len);
173 CPubKey DiceFundingPk(CScript scriptPubKey)
175 CPubKey pk; uint8_t *ptr,*dest; int32_t i;
176 if ( scriptPubKey.size() == 35 )
178 ptr = (uint8_t *)scriptPubKey.data();
179 dest = (uint8_t *)pk.begin();
182 } else fprintf(stderr,"DiceFundingPk invalid size.%d\n",(int32_t)scriptPubKey.size());
186 uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv) // max 1 vout per txid used
188 int32_t i; uint8_t _entropy[32],_hentropy[32]; bits256 tmp256,txidpub,txidpriv,mypriv,mypub,ssecret,ssecret2; uint256 hentropy;
189 memset(&hentropy,0,32);
190 endiancpy(txidpriv.bytes,(uint8_t *)&_txidpriv,32);
191 txidpriv.bytes[0] &= 0xf8, txidpriv.bytes[31] &= 0x7f, txidpriv.bytes[31] |= 0x40;
192 txidpub = curve25519(txidpriv,curve25519_basepoint9());
194 Myprivkey(tmp256.bytes);
195 vcalc_sha256(0,mypriv.bytes,tmp256.bytes,32);
196 mypriv.bytes[0] &= 0xf8, mypriv.bytes[31] &= 0x7f, mypriv.bytes[31] |= 0x40;
197 mypub = curve25519(mypriv,curve25519_basepoint9());
199 ssecret = curve25519(mypriv,txidpub);
200 ssecret2 = curve25519(txidpriv,mypub);
201 if ( memcmp(ssecret.bytes,ssecret2.bytes,32) == 0 )
203 vcalc_sha256(0,(uint8_t *)&_entropy,ssecret.bytes,32);
204 vcalc_sha256(0,(uint8_t *)&_hentropy,_entropy,32);
205 endiancpy((uint8_t *)&entropy,_entropy,32);
206 endiancpy((uint8_t *)&hentropy,_hentropy,32);
211 fprintf(stderr,"%02x",ssecret.bytes[i]);
212 fprintf(stderr," ssecret\n");
214 fprintf(stderr,"%02x",ssecret2.bytes[i]);
215 fprintf(stderr," ssecret2 dont match\n");
217 //char str[65],str2[65];
218 //fprintf(stderr,"generated house hentropy.%s <- entropy.%s\n",uint256_str(str,hentropy),uint256_str(str2,entropy));
222 uint64_t DiceCalc(int64_t bet,int64_t odds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks,uint256 houseentropy,uint256 bettorentropy)
224 uint8_t buf[64],_house[32],_bettor[32]; uint64_t winnings; arith_uint256 house,bettor; char str[65],str2[65];
228 if ( bet < minbet || bet > maxbet || odds > maxodds )
230 fprintf(stderr,"bet size violation %.8f\n",(double)bet/COIN);
233 //fprintf(stderr,"calc house entropy %s vs bettor %s\n",uint256_str(str,houseentropy),uint256_str(str2,bettorentropy));
235 endiancpy(buf,(uint8_t *)&houseentropy,32);
236 endiancpy(&buf[32],(uint8_t *)&bettorentropy,32);
237 vcalc_sha256(0,(uint8_t *)&_house,buf,64);
238 endiancpy((uint8_t *)&house,_house,32);
240 endiancpy(buf,(uint8_t *)&bettorentropy,32);
241 endiancpy(&buf[32],(uint8_t *)&houseentropy,32);
242 vcalc_sha256(0,(uint8_t *)&_bettor,buf,64);
243 endiancpy((uint8_t *)&bettor,_bettor,32);
245 bettor = (bettor / arith_uint256(odds));
246 if ( bettor >= house )
247 winnings = bet * (odds+1);
252 CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
254 CScript opret; uint8_t evalcode = EVAL_DICE;
255 opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << timeoutblocks);
259 uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks)
261 std::vector<uint8_t> vopret; uint8_t *script,e,f;
262 GetOpReturnData(scriptPubKey, vopret);
263 script = (uint8_t *)vopret.data();
264 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 )
266 if ( e == EVAL_DICE && f == 'F' )
272 CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid,uint256 hash,uint256 proof)
274 CScript opret; uint8_t evalcode = EVAL_DICE;
275 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid << hash << proof);
279 uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid,uint256 &hash,uint256 &proof)
281 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,timeoutblocks;
282 GetOpReturnData(scriptPubKey,vopret);
283 if ( vopret.size() > 2 )
285 script = (uint8_t *)vopret.data();
286 if ( script[0] == EVAL_DICE )
288 if ( script[1] == 'F' )
290 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 )
295 } else fprintf(stderr,"unmarshal error for F\n");
297 else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid; ss >> hash; ss >> proof) != 0 )
299 if ( e == EVAL_DICE && (f == 'B' || f == 'W' || f == 'L' || f == 'T' || f == 'E') )
301 else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f);
303 } else fprintf(stderr,"script[0] %02x != EVAL_DICE\n",script[0]);
304 } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
308 uint256 DiceGetEntropy(CTransaction tx,uint8_t reffuncid)
310 uint256 hash,fundingtxid,proof; uint64_t sbits; int32_t numvouts;
311 if ( (numvouts= tx.vout.size()) > 0 && DecodeDiceOpRet(tx.GetHash(),tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof) == reffuncid )
316 uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
319 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
321 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
322 return(tx.vout[v].nValue);
327 int64_t DiceAmounts(uint64_t &inputs,uint64_t &outputs,struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
329 CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t assetoshis;
330 numvins = tx.vin.size();
331 numvouts = tx.vout.size();
332 inputs = outputs = 0;
333 for (i=0; i<numvins; i++)
335 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
337 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
338 return eval->Invalid("always should find vin, but didnt");
341 if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
342 inputs += assetoshis;
346 for (i=0; i<numvouts; i++)
348 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
349 if ( (assetoshis= IsDicevout(cp,tx,i)) != 0 )
350 outputs += assetoshis;
352 return(inputs - outputs);
355 bool DiceIsmine(const CScript scriptPubKey)
357 char destaddr[64],myaddr[64];
358 Getscriptaddress(destaddr,scriptPubKey);
359 Getscriptaddress(myaddr,CScript() << Mypubkey() << OP_CHECKSIG);
360 return(strcmp(destaddr,myaddr) == 0);
363 int32_t DiceIsWinner(uint256 &entropy,uint256 txid,CTransaction tx,CTransaction vinTx,uint256 bettorentropy,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks,uint256 fundingtxid)
365 uint64_t vinsbits,winnings; uint256 vinproof,vinfundingtxid,hentropy,hentropy2; uint8_t funcid;
366 //char str[65],str2[65];
367 if ( vinTx.vout.size() > 1 && DiceIsmine(vinTx.vout[1].scriptPubKey) != 0 && vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 )
369 if ( ((funcid= DecodeDiceOpRet(txid,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,hentropy,vinproof)) == 'E' || funcid == 'W' || funcid == 'L') && sbits == vinsbits && fundingtxid == vinfundingtxid )
371 hentropy2 = DiceHashEntropy(entropy,vinTx.vin[0].prevout.hash);
372 if ( hentropy == hentropy2 )
374 winnings = DiceCalc(tx.vout[1].nValue,tx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,entropy,bettorentropy);
375 char str[65]; fprintf(stderr,"%s winnings %.8f bet %.8f at odds %d:1\n",uint256_str(str,tx.GetHash()),(double)winnings/COIN,(double)tx.vout[1].nValue/COIN,(int32_t)(tx.vout[2].nValue-10000));
376 //fprintf(stderr,"I am house entropy %.8f entropy.(%s) vs %s -> winnings %.8f\n",(double)vinTx.vout[0].nValue/COIN,uint256_str(str,entropy),uint256_str(str2,hash),(double)winnings/COIN);
379 // queue 'L' losing tx
384 // queue 'W' winning tx
387 } else fprintf(stderr,"hentropy != hentropy2\n");
388 } else fprintf(stderr,"funcid.%c sbits %llx vs %llx cmp.%d\n",funcid,(long long)sbits,(long long)vinsbits,fundingtxid == vinfundingtxid);
389 } //else fprintf(stderr,"notmine or not CC\n");
393 bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks)
395 fprintf(stderr,"DiceVerifyTimeout needs to be implemented\n");
399 bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
401 uint256 txid,fundingtxid,vinfundingtxid,vinhentropy,vinproof,hashBlock,hash,proof,entropy; int64_t minbet,maxbet,maxodds,timeoutblocks,odds,winnings; uint64_t vinsbits,sbits,amount,inputs,outputs,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,iswin; uint8_t funcid; CScript fundingPubKey; CTransaction fundingTx,vinTx,vinofvinTx; char CCaddr[64];
402 numvins = tx.vin.size();
403 numvouts = tx.vout.size();
404 preventCCvins = preventCCvouts = -1;
406 return eval->Invalid("no vouts");
410 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
412 if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
413 return eval->Invalid("cant find fundingtxid");
414 else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 'F' )
415 return eval->Invalid("fundingTx not valid");
416 fundingPubKey = fundingTx.vout[1].scriptPubKey;
420 //vins.*: normal inputs
421 //vout.0: CC vout for funding
422 //vout.1: normal marker vout for easy searching
423 //vout.2: normal change
424 //vout.n-1: opreturn 'F' sbits minbet maxbet maxodds timeoutblocks
425 return eval->Invalid("unexpected DiceValidate for createfunding");
427 case 'E': // check sig of vin to match fundingtxid in the 'B' tx
428 //vins.*: normal inputs
429 //vout.0: CC vout for locked entropy funds
430 //vout.1: tag to owner address for entropy funds
431 //vout.2: normal change
432 //vout.n-1: opreturn 'E' sbits fundingtxid hentropy
433 return eval->Invalid("unexpected DiceValidate for addfunding entropy");
436 //vin.0: entropy txid from house
437 //vins.1+: normal inputs
438 //vout.0: CC vout for locked entropy
439 //vout.1: CC vout for locked bet
440 //vout.2: tag for bettor's address (txfee + odds)
442 //vout.n-1: opreturn 'B' sbits fundingtxid entropy
445 if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
446 return eval->Invalid("vin.0 is normal for bet");
447 else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
448 return eval->Invalid("vout.0 is normal for bet");
449 else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
450 return eval->Invalid("vout.1 is normal for bet");
451 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
452 return eval->Invalid("always should find vin.0, but didnt for bet");
453 else if ( vinTx.vout[1].scriptPubKey != fundingPubKey )
454 return eval->Invalid("entropy tx not fundingPubKey for bet");
455 else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,vinTx.vout[tx.vin[0].prevout.n].nValue) == 0 )
456 return eval->Invalid("vout[0] != entropy nValue for bet");
457 else if ( ConstrainVout(tx.vout[1],1,cp->unspendableCCaddr,0) == 0 )
458 return eval->Invalid("vout[1] constrain violation for bet");
459 else if ( tx.vout[2].nValue >= txfee+maxodds || tx.vout[2].nValue < txfee )
460 return eval->Invalid("vout[2] nValue violation for bet");
461 else if ( eval->GetTxUnconfirmed(vinTx.vin[0].prevout.hash,vinofvinTx,hashBlock) == 0 || vinofvinTx.vout.size() < 1 )
462 return eval->Invalid("always should find vinofvin.0, but didnt for bet");
463 else if ( vinTx.vin[0].prevout.hash != fundingtxid )
465 if ( vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey != fundingPubKey )
467 uint8_t *ptr0,*ptr1; int32_t i; char str[65];
468 fprintf(stderr,"bidTx.%s\n",uint256_str(str,txid));
469 fprintf(stderr,"entropyTx.%s v%d\n",uint256_str(str,tx.vin[0].prevout.hash),(int32_t)tx.vin[0].prevout.n);
470 fprintf(stderr,"entropyTx vin0 %s v%d\n",uint256_str(str,vinTx.vin[0].prevout.hash),(int32_t)vinTx.vin[0].prevout.n);
471 ptr0 = (uint8_t *)vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey.data();
472 ptr1 = (uint8_t *)fundingPubKey.data();
473 for (i=0; i<vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey.size(); i++)
474 fprintf(stderr,"%02x",ptr0[i]);
475 fprintf(stderr," script vs ");
476 for (i=0; i<fundingPubKey.size(); i++)
477 fprintf(stderr,"%02x",ptr1[i]);
478 fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch %s\n",funcid,vinTx.vin[0].prevout.n,uint256_str(str,vinTx.vin[0].prevout.hash));
479 return eval->Invalid("vin1 of entropy tx not fundingPubKey for bet");
482 if ( (iswin= DiceIsWinner(entropy,txid,tx,vinTx,hash,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
484 // will only happen for fundingPubKey
485 DiceQueue(iswin,sbits,fundingtxid,txid);
491 //vin.0: normal input
492 //vin.1: betTx CC vout.0 entropy from bet
493 //vin.2: betTx CC vout.1 bet amount from bet
494 //vin.3+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T'
495 //vout.1: tag to owner address for entropy funds
497 DiceAmounts(inputs,outputs,cp,eval,tx);
498 if ( IsCCInput(tx.vin[1].scriptSig) == 0 || IsCCInput(tx.vin[2].scriptSig) == 0 )
499 return eval->Invalid("vin0 or vin1 normal vin for bet");
500 else if ( tx.vin[1].prevout.hash != tx.vin[2].prevout.hash )
501 return eval->Invalid("vin0 != vin1 prevout.hash for bet");
502 else if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 )
503 return eval->Invalid("always should find vin.0, but didnt for wlt");
504 else if ( vinTx.vout.size() < 3 || DecodeDiceOpRet(tx.vin[1].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,vinhentropy,vinproof) != 'B' )
505 return eval->Invalid("not betTx for vin0/1 for wlt");
506 else if ( sbits != vinsbits || fundingtxid != vinfundingtxid )
507 return eval->Invalid("sbits or fundingtxid mismatch for wlt");
508 else if ( fundingPubKey != tx.vout[1].scriptPubKey )
509 return eval->Invalid("tx.vout[1] != fundingPubKey for wlt");
512 //vout.0: funding CC to entropy owner
513 //vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof
514 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,inputs) == 0 )
515 return eval->Invalid("vout[0] != inputs-txfee for loss");
516 else if ( tx.vout[2].scriptPubKey != fundingPubKey )
518 if ( tx.vout[2].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[2].scriptPubKey.data())[0] != 0x6a )
519 return eval->Invalid("vout[2] not send to fundingPubKey for loss");
525 //vout.0: funding CC change to entropy owner
526 //vout.2: normal output to bettor's address
527 //vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
528 odds = vinTx.vout[2].nValue - txfee;
529 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
530 return eval->Invalid("vout[0] != inputs-txfee for win/timeout");
531 else if ( tx.vout[2].scriptPubKey != vinTx.vout[2].scriptPubKey )
532 return eval->Invalid("vout[2] scriptPubKey mismatch for win/timeout");
533 else if ( tx.vout[2].nValue != (odds+1)*vinTx.vout[1].nValue )
534 return eval->Invalid("vout[2] payut mismatch for win/timeout");
535 else if ( inputs != (outputs + tx.vout[2].nValue) && inputs != (outputs + tx.vout[2].nValue+txfee) )
537 fprintf(stderr,"inputs %.8f != outputs %.8f + %.8f\n",(double)inputs/COIN,(double)outputs/COIN,(double)tx.vout[2].nValue/COIN);
538 return eval->Invalid("CC funds mismatch for win/timeout");
540 else if ( tx.vout[3].scriptPubKey != fundingPubKey )
542 if ( tx.vout[3].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[3].scriptPubKey.data())[0] != 0x6a )
543 return eval->Invalid("vout[3] not send to fundingPubKey for win/timeout");
545 iswin = (funcid == 'W');
549 //char str[65],str2[65];
550 entropy = DiceGetEntropy(vinTx,'B');
551 vcalc_sha256(0,(uint8_t *)&hash,(uint8_t *)&proof,32);
552 //fprintf(stderr,"calculated house hentropy.%s\n",uint256_str(str,hash));
553 //fprintf(stderr,"verify house entropy %s vs bettor %s\n",uint256_str(str,proof),uint256_str(str2,entropy));
554 winnings = DiceCalc(vinTx.vout[1].nValue,vinTx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,proof,entropy);
555 if ( (winnings == 0 && iswin > 0) || (winnings > 0 && iswin < 0) )
556 return eval->Invalid("DiceCalc mismatch for win/loss");
558 else if ( DiceVerifyTimeout(vinTx,timeoutblocks) == 0 )
559 return eval->Invalid("invalid timeout claim for timeout");
563 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
568 uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
570 char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hash,proof,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
571 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
572 GetCCaddress(cp,coinaddr,pk);
573 SetCCunspents(unspentOutputs,coinaddr);
574 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
576 txid = it->first.txhash;
577 vout = (int32_t)it->first.index;
578 if ( it->second.satoshis < 1000000 )
580 //fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
581 for (j=0; j<mtx.vin.size(); j++)
582 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
584 if ( j != mtx.vin.size() )
586 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
588 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
590 if ( funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T' )
592 if ( total != 0 && maxinputs != 0 )
593 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
594 totalinputs += it->second.satoshis;
596 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
599 } else fprintf(stderr,"null funcid\n");
605 uint64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey dicepk,uint256 reffundingtxid)
607 char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 hash,txid,proof,hashBlock,fundingtxid; CScript fundingPubKey; CTransaction tx,vinTx; int32_t vout,first=0,n=0; uint8_t funcid;
608 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
609 if ( GetTransaction(reffundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) != 0 )
611 fundingPubKey = tx.vout[1].scriptPubKey;
613 GetCCaddress(cp,coinaddr,dicepk);
614 SetCCunspents(unspentOutputs,coinaddr);
616 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
618 txid = it->first.txhash;
619 vout = (int32_t)it->first.index;
620 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
622 //char str[65],str2[65];
623 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
625 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
627 if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 10000 && (funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T') )
629 if ( funcid != 'F' && funcid != 'T' )
632 fprintf(stderr,"%s.(%c %.8f) ",uint256_str(str,txid),funcid,(double)nValue/COIN);
634 totalinputs += nValue;
635 if ( first == 0 && (funcid == 'E' || funcid == 'W' || funcid == 'L') )
637 fprintf(stderr,"check first\n");
638 if ( fundingPubKey == tx.vout[1].scriptPubKey )
640 if ( funcid == 'E' && fundingtxid != tx.vin[0].prevout.hash )
642 if ( GetTransaction(tx.vin[0].prevout.hash,vinTx,hashBlock,false) == 0 )
644 fprintf(stderr,"cant find entropy vin0 %s or vin0prev %d vouts[%d]\n",uint256_str(str,tx.vin[0].prevout.hash),tx.vin[0].prevout.n,(int32_t)vinTx.vout.size());
647 if ( vinTx.vout[tx.vin[0].prevout.n].scriptPubKey != fundingPubKey )
649 uint8_t *ptr0,*ptr1; int32_t i; char str[65];
650 ptr0 = (uint8_t *)vinTx.vout[tx.vin[0].prevout.n].scriptPubKey.data();
651 ptr1 = (uint8_t *)fundingPubKey.data();
652 for (i=0; i<vinTx.vout[tx.vin[0].prevout.n].scriptPubKey.size(); i++)
653 fprintf(stderr,"%02x",ptr0[i]);
654 fprintf(stderr," script vs ");
655 for (i=0; i<fundingPubKey.size(); i++)
656 fprintf(stderr,"%02x",ptr1[i]);
657 fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch %s\n",funcid,tx.vin[0].prevout.n,uint256_str(str,tx.vin[0].prevout.hash));
660 } //else fprintf(stderr,"not E or is funding\n");
662 entropyval = tx.vout[0].nValue;
667 uint8_t *ptr0,*ptr1; int32_t i; char str[65];
668 ptr0 = (uint8_t *)tx.vout[1].scriptPubKey.data();
669 ptr1 = (uint8_t *)fundingPubKey.data();
670 for (i=0; i<tx.vout[1].scriptPubKey.size(); i++)
671 fprintf(stderr,"%02x",ptr0[i]);
672 fprintf(stderr," script vs ");
673 for (i=0; i<fundingPubKey.size(); i++)
674 fprintf(stderr,"%02x",ptr1[i]);
675 fprintf(stderr," (%c) tx vin.%d fundingPubKey mismatch %s\n",funcid,tx.vin[0].prevout.n,uint256_str(str,tx.vin[0].prevout.hash));
678 } else fprintf(stderr,"%s %c refsbits.%llx sbits.%llx nValue %.8f\n",uint256_str(str,txid),funcid,(long long)refsbits,(long long)sbits,(double)nValue/COIN);
679 } //else fprintf(stderr,"else case funcid (%c) %d %s vs %s\n",funcid,funcid,uint256_str(str,reffundingtxid),uint256_str(str2,fundingtxid));
680 } //else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
683 fprintf(stderr,"numentropy tx %d: %.8f\n",n,(double)totalinputs/COIN);
687 bool DicePlanExists(CScript &fundingPubKey,uint256 &fundingtxid,struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks)
689 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
690 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
691 GetCCaddress(cp,CCaddr,dicepk);
692 SetCCtxids(txids,cp->normaladdr);
693 if ( fundingtxid != zeroid ) // avoid scan unless creating new funding plan
695 if ( GetTransaction(fundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
697 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' && sbits == refsbits )
699 fundingPubKey = tx.vout[1].scriptPubKey;
705 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
707 //int height = it->first.blockHeight;
708 txid = it->first.txhash;
709 if ( fundingtxid != zeroid && txid != fundingtxid )
711 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
713 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' )
715 if ( sbits == refsbits )
717 fundingPubKey = tx.vout[1].scriptPubKey;
727 struct CCcontract_info *Diceinit(CScript &fundingPubKey,uint256 reffundingtxid,struct CCcontract_info *C,char *planstr,uint64_t &txfee,CPubKey &mypk,CPubKey &dicepk,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks)
729 struct CCcontract_info *cp; int32_t cmpflag;
730 cp = CCinit(C,EVAL_DICE);
733 mypk = pubkey2pk(Mypubkey());
734 dicepk = GetUnspendable(cp,0);
735 sbits = stringbits(planstr);
736 if ( reffundingtxid == zeroid )
739 if ( DicePlanExists(fundingPubKey,reffundingtxid,cp,sbits,dicepk,minbet,maxbet,maxodds,timeoutblocks) != cmpflag )
741 fprintf(stderr,"Dice plan (%s) already exists cmpflag.%d\n",planstr,cmpflag);
747 UniValue DiceInfo(uint256 diceid)
749 UniValue result(UniValue::VOBJ); CPubKey dicepk; uint256 hashBlock,entropytxid; CTransaction vintx; int64_t minbet,maxbet,maxodds,timeoutblocks; uint64_t sbits,funding,entropyval; char str[67],numstr[65]; struct CCcontract_info *cp,C;
750 if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 )
752 fprintf(stderr,"cant find fundingtxid\n");
753 result.push_back(Pair("error","cant find fundingtxid"));
756 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 0 )
758 fprintf(stderr,"fundingtxid isnt dice creation txid\n");
759 result.push_back(Pair("error","fundingtxid isnt dice creation txid"));
762 result.push_back(Pair("result","success"));
763 result.push_back(Pair("fundingtxid",uint256_str(str,diceid)));
764 unstringbits(str,sbits);
765 result.push_back(Pair("name",str));
766 result.push_back(Pair("sbits",sbits));
767 sprintf(numstr,"%.8f",(double)minbet/COIN);
768 result.push_back(Pair("minbet",numstr));
769 sprintf(numstr,"%.8f",(double)maxbet/COIN);
770 result.push_back(Pair("maxbet",numstr));
771 result.push_back(Pair("maxodds",maxodds));
772 result.push_back(Pair("timeoutblocks",timeoutblocks));
773 cp = CCinit(&C,EVAL_DICE);
774 dicepk = GetUnspendable(cp,0);
775 funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,diceid);
776 sprintf(numstr,"%.8f",(double)funding/COIN);
777 result.push_back(Pair("funding",numstr));
783 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,timeoutblocks; char str[65];
784 cp = CCinit(&C,EVAL_DICE);
785 SetCCtxids(addressIndex,cp->normaladdr);
786 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
788 txid = it->first.txhash;
789 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
791 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 0 )
793 result.push_back(uint256_str(str,txid));
800 std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
802 CMutableTransaction mtx; uint256 zero; CScript fundingPubKey; CPubKey mypk,dicepk; int64_t a,b,c,d; uint64_t sbits; struct CCcontract_info *cp,C;
803 if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || timeoutblocks < 0 || timeoutblocks > 1440 )
805 fprintf(stderr,"negative parameter error\n");
808 memset(&zero,0,sizeof(zero));
809 if ( (cp= Diceinit(fundingPubKey,zero,&C,planstr,txfee,mypk,dicepk,sbits,a,b,c,d)) == 0 )
811 if ( AddNormalinputs(mtx,mypk,funds+3*txfee,60) > 0 )
813 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk));
814 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
815 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG));
816 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,timeoutblocks)));
818 fprintf(stderr,"cant find enough inputs\n");
822 std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
824 CMutableTransaction mtx; CScript fundingPubKey,scriptPubKey; uint256 entropy,hentropy; CPubKey mypk,dicepk; uint64_t sbits; struct CCcontract_info *cp,C; int64_t minbet,maxbet,maxodds,timeoutblocks;
827 fprintf(stderr,"negative parameter error\n");
830 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
832 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
835 uint8_t *ptr0,*ptr1; int32_t i;
836 ptr0 = (uint8_t *)scriptPubKey.data();
837 ptr1 = (uint8_t *)fundingPubKey.data();
839 fprintf(stderr,"%02x",ptr0[i]);
840 fprintf(stderr," script vs ");
842 fprintf(stderr,"%02x",ptr1[i]);
843 fprintf(stderr," funding\n");
845 if ( scriptPubKey == fundingPubKey )
847 if ( AddNormalinputs(mtx,mypk,amount+2*txfee,60) > 0 )
849 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
850 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk));
851 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
852 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('E',sbits,fundingtxid,hentropy,zeroid)));
853 } else fprintf(stderr,"cant find enough inputs\n");
854 } else fprintf(stderr,"only fund creator can add more funds (entropy)\n");
858 std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds)
860 CMutableTransaction mtx; CScript fundingPubKey; CPubKey mypk,dicepk; uint64_t sbits,entropyval; int64_t funding,minbet,maxbet,maxodds,timeoutblocks; uint256 entropytxid,entropy,hentropy; struct CCcontract_info *cp,C;
861 if ( bet < 0 || odds < 1 )
863 fprintf(stderr,"negative parameter error\n");
866 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
868 if ( bet < minbet || bet > maxbet || odds > maxodds )
870 fprintf(stderr,"Dice plan %s illegal bet %.8f: minbet %.8f maxbet %.8f or odds %d vs max.%d\n",planstr,(double)bet/COIN,(double)minbet/COIN,(double)maxbet/COIN,(int32_t)odds,(int32_t)maxodds);
873 if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid)) >= 2*bet*odds+txfee && entropyval != 0 )
875 if ( myIsutxo_spentinmempool(entropytxid,0) != 0 )
877 fprintf(stderr,"entropy txid is spent\n");
880 mtx.vin.push_back(CTxIn(entropytxid,0,CScript()));
881 if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 )
883 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
884 mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk));
885 mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk));
886 mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
887 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('B',sbits,fundingtxid,entropy,zeroid)));
888 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN);
890 if ( entropyval == 0 && funding != 0 )
891 fprintf(stderr,"cant find dice entropy inputs\n");
892 else fprintf(stderr,"cant find dice inputs\n");
896 std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout)
898 CMutableTransaction mtx; CScript scriptPubKey,fundingPubKey; CTransaction betTx,entropyTx; uint256 hentropyproof,entropytxid,hashBlock,bettorentropy,entropy,hentropy; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int64_t inputs,CCchange=0,odds,fundsneeded,minbet,maxbet,maxodds,timeoutblocks; uint8_t funcid; int32_t iswin=0; uint64_t entropyval,sbits;
900 //char str[65]; fprintf(stderr,"DiceBetFinish.%s %s\n",planstr,uint256_str(str,bettxid));
901 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
903 fprintf(stderr,"Diceinit error\n");
906 fundingpk = DiceFundingPk(fundingPubKey);
907 if ( winlosetimeout != 0 )
909 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
910 if ( scriptPubKey != fundingPubKey )
912 fprintf(stderr,"only dice fund creator can submit winner or loser\n");
916 if ( AddNormalinputs(mtx,mypk,txfee,1) == 0 )
918 fprintf(stderr,"no txfee inputs for win/lose\n");
921 if ( GetTransaction(bettxid,betTx,hashBlock,false) != 0 && GetTransaction(betTx.vin[0].prevout.hash,entropyTx,hashBlock,false) != 0 )
923 bettorentropy = DiceGetEntropy(betTx,'B');
924 if ( winlosetimeout == 0 || (iswin= DiceIsWinner(hentropyproof,bettxid,betTx,entropyTx,bettorentropy,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
926 winlosetimeout = iswin;
927 if ( iswin == winlosetimeout )
929 if ( myIsutxo_spentinmempool(bettxid,0) != 0 || myIsutxo_spentinmempool(bettxid,1) != 0 )
931 fprintf(stderr,"bettxid already spent\n");
934 //fprintf(stderr,"iswin.%d matches\n",iswin);
935 mtx.vin.push_back(CTxIn(bettxid,0,CScript()));
936 mtx.vin.push_back(CTxIn(bettxid,1,CScript()));
940 if ( DiceVerifyTimeout(betTx,timeoutblocks) == 0 ) // hasnt timed out yet
942 fprintf(stderr,"timeout is not supported yet\n");
947 hentropy = hentropyproof = zeroid;
954 odds = (betTx.vout[2].nValue - txfee);
955 if ( odds < 1 || odds > maxodds )
957 fprintf(stderr,"illegal odds.%d vs maxodds.%d\n",(int32_t)odds,(int32_t)maxodds);
960 CCchange = betTx.vout[0].nValue;
961 fundsneeded = txfee + odds*betTx.vout[1].nValue;
962 if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60)) > 0 )
964 if ( inputs > fundsneeded )
965 CCchange += (inputs - fundsneeded);
966 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk));
967 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
968 mtx.vout.push_back(CTxOut((odds+1) * betTx.vout[1].nValue,betTx.vout[2].scriptPubKey));
972 fprintf(stderr,"not enough inputs for %.8f\n",(double)fundsneeded/COIN);
979 mtx.vout.push_back(MakeCC1vout(cp->evalcode,betTx.vout[0].nValue + betTx.vout[1].nValue,dicepk));
980 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
982 if ( winlosetimeout != 0 )
983 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
985 //char str[65],str2[65];
986 //fprintf(stderr,"iswin.%d house entropy %s vs bettor %s\n",iswin,uint256_str(str,hentropyproof),uint256_str(str2,bettorentropy));
987 return(FinalizeCCTx(0,cp,mtx,fundingpk,txfee,EncodeDiceOpRet(funcid,sbits,fundingtxid,hentropy,hentropyproof)));
988 } else fprintf(stderr,"iswin.%d does not match.%d\n",iswin,winlosetimeout);
993 fprintf(stderr,"iswin.%d winlosetimeout.%d\n",iswin,winlosetimeout);
998 fprintf(stderr,"couldnt find bettx or entropytx\n");
1002 double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid)
1004 CScript fundingPubKey,scriptPubKey; CTransaction spenttx,betTx; uint256 hash,proof,txid,hashBlock,spenttxid; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int32_t i,result,vout,n=0; int64_t minbet,maxbet,maxodds,timeoutblocks; uint64_t sbits; char coinaddr[64]; std::string res;
1005 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
1007 fprintf(stderr,"Diceinit error\n");
1010 fundingpk = DiceFundingPk(fundingPubKey);
1011 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
1012 GetCCaddress(cp,coinaddr,dicepk);
1013 if ( bettxid == zeroid ) // scan
1015 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
1016 SetCCunspents(unspentOutputs,coinaddr);
1017 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
1019 txid = it->first.txhash;
1020 vout = (int32_t)it->first.index;
1021 if ( GetTransaction(txid,betTx,hashBlock,false) != 0 && betTx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
1023 if ( DecodeDiceOpRet(txid,betTx.vout[betTx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof) == 'B' )
1025 res = DiceBetFinish(&result,txfee,planstr,fundingtxid,txid,scriptPubKey == fundingPubKey);
1028 mySendrawtransaction(res);
1034 if ( scriptPubKey == fundingPubKey )
1036 for (i=0; i<=n; i++)
1038 res = DiceAddfunding(txfee,planstr,fundingtxid,COIN);
1039 mySendrawtransaction(res);
1046 if ( (vout= myIsutxo_spent(spenttxid,bettxid,1)) >= 0 )
1048 if ( GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() > 2 )
1050 if ( spenttx.vout[2].scriptPubKey == fundingPubKey )
1052 else return((double)spenttx.vout[2].nValue/COIN);
1055 else if ( scriptPubKey == fundingPubKey )
1056 res = DiceBetFinish(&result,txfee,planstr,fundingtxid,bettxid,1);
1057 else res = DiceBetFinish(&result,txfee,planstr,fundingtxid,bettxid,0);
1060 mySendrawtransaction(res);
1062 if ( (vout= myIsutxo_spent(spenttxid,bettxid,1)) >= 0 )
1064 if ( GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() >= 2 )
1066 if ( spenttx.vout[2].scriptPubKey == fundingPubKey || ((uint8_t *)spenttx.vout[2].scriptPubKey.data())[0] == 0x6a )
1068 else return((double)spenttx.vout[2].nValue/COIN);
1071 fprintf(stderr,"didnt find dicefinish tx\n");