]> Git Repo - VerusCoin.git/blame - src/cc/dice.cpp
Test
[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
7137a022 18// timeout, validate, verify win/loss can be used for entropy
afef48c0 19
cfea7a46 20/*
10078e85 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.
22
9025093e 23 1. CC vout locks "house" funds with hash(entropy)
10078e85 24 2. bettor submits bet, with entropy, odds, houseid and sends combined amount into another CC vout.
9025093e 25 3. house account sends funds to winner/loser with proof of entropy
26 4. if timeout, bettor gets refund
10078e85 27
28 2. and 3. can be done in mempool
9025093e 29
30 The house commits to an entropy value by including the hash of the entropy value in the 'E' transaction.
31
753a6f92 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.
33
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.
35
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
7eb60411 37
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.
39
40createfunding:
41 vins.*: normal inputs
42 vout.0: CC vout for funding
32e3be87 43 vout.1: owner vout
44 vout.2: dice marker address vout for easy searching
45 vout.3: normal change
7eb60411 46 vout.n-1: opreturn 'F' sbits minbet maxbet maxodds timeoutblocks
47
48addfunding (entropy):
49 vins.*: normal inputs
50 vout.0: CC vout for locked entropy funds
51 vout.1: tag to owner address for entropy funds
52 vout.2: normal change
53 vout.n-1: opreturn 'E' sbits fundingtxid hentropy
54
55bet:
4d2b7323 56 vin.0: entropy txid from house (must validate vin0 of 'E')
7eb60411 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)
61 vout.3: change
62 vout.n-1: opreturn 'B' sbits fundingtxid entropy
63
7eb60411 64loser:
65 vin.0: betTx CC vout.0 entropy from bet
66 vin.1: betTx CC vout.1 bet amount from bet
02409974 67 vin.2+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T'
7eb60411 68 vout.0: funding CC to entropy owner
69 vout.1: tag to owner address for entropy funds
4d2b7323 70 vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof
71
72winner:
73 same as loser, but vout.2 is winnings
74 vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
7eb60411 75
02409974 76timeout:
4d2b7323 77 same as winner, just without hentropy or proof
7eb60411 78
10078e85 79 */
cfea7a46 80
ae748eaf 81#include "../endian.h"
82
e787eaee 83static uint256 bettxids[128];
7377f6ea 84
85struct dicefinish_info
86{
e787eaee 87 uint256 fundingtxid,bettxid;
7377f6ea 88 uint64_t sbits;
89 int32_t iswin;
90};
91
92void *dicefinish(void *_ptr)
93{
3528fb20 94 char str[65],str2[65],name[32]; std::string res; int32_t i,duplicate=0; struct dicefinish_info *ptr;
7377f6ea 95 ptr = (struct dicefinish_info *)_ptr;
96 sleep(1);
e787eaee 97 for (i=0; i<sizeof(bettxids)/sizeof(*bettxids); i++)
98 if ( bettxids[i] == ptr->bettxid )
7377f6ea 99 {
100 duplicate = 1;
101 break;
102 }
103 if ( duplicate == 0 )
104 {
e787eaee 105 for (i=0; i<sizeof(bettxids)/sizeof(*bettxids); i++)
106 if ( bettxids[i] == zeroid )
7377f6ea 107 {
e787eaee 108 bettxids[i] = ptr->bettxid;
7377f6ea 109 break;
110 }
e787eaee 111 if ( i == sizeof(bettxids)/sizeof(*bettxids) )
112 bettxids[rand() % i] = ptr->bettxid;
7377f6ea 113 }
114 unstringbits(name,ptr->sbits);
c8624d40 115 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));
3528fb20 116 if ( duplicate == 0 )
117 {
cfdc3770 118 CTransaction tx; uint256 txid; char str[65]; int32_t result;
119 res = DiceWinLoseTimeout(&result,0,name,ptr->fundingtxid,ptr->bettxid,ptr->iswin);
f4d2c1a3 120 if ( result != 0 && res.empty() == 0 && res.size() > 64 && is_hexstr((char *)res.c_str(),0) > 64 )
a88b9554 121 {
a88b9554 122 LOCK(cs_main);
123 if ( DecodeHexTx(tx,res) != 0 )
124 {
125 txid = tx.GetHash();
126 RelayTransaction(tx);
8dc5d279 127 fprintf(stderr,"%s\nresult.(%s)\n",res.c_str(),uint256_str(str,txid));
a88b9554 128 }
f4d2c1a3 129 }
3528fb20 130 }
7377f6ea 131 free(ptr);
132 return(0);
133}
134
e787eaee 135void DiceQueue(int32_t iswin,uint64_t sbits,uint256 fundingtxid,uint256 bettxid)
7377f6ea 136{
e8f9de07 137 struct dicefinish_info *ptr = (struct dicefinish_info *)calloc(1,sizeof(*ptr));
7377f6ea 138 ptr->fundingtxid = fundingtxid;
e787eaee 139 ptr->bettxid = bettxid;
7377f6ea 140 ptr->sbits = sbits;
141 ptr->iswin = iswin;
142 if ( ptr != 0 && pthread_create((pthread_t *)malloc(sizeof(pthread_t)),NULL,dicefinish,(void *)ptr) != 0 )
143 {
144 fprintf(stderr,"DiceQueue.%d\n",iswin);
145 } // small memory leak per DiceQueue
7377f6ea 146}
147
ae748eaf 148void endiancpy(uint8_t *dest,uint8_t *src,int32_t len)
149{
150 int32_t i,j=0;
151#if defined(WORDS_BIGENDIAN)
152 for (i=31; i>=0; i--)
153 dest[j++] = src[i];
154#else
17bc6201 155 memcpy(dest,src,len);
ae748eaf 156#endif
157}
158
dfe4c146 159uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv) // max 1 vout per txid used
8138fad2 160{
ae748eaf 161 int32_t i; uint8_t _entropy[32],_hentropy[32]; bits256 tmp256,txidpub,txidpriv,mypriv,mypub,ssecret,ssecret2; uint256 hentropy;
72362bbe 162 memset(&hentropy,0,32);
e0e655fe 163 endiancpy(txidpriv.bytes,(uint8_t *)&_txidpriv,32);
d176d2df 164 txidpriv.bytes[0] &= 0xf8, txidpriv.bytes[31] &= 0x7f, txidpriv.bytes[31] |= 0x40;
165 txidpub = curve25519(txidpriv,curve25519_basepoint9());
166
167 Myprivkey(tmp256.bytes);
168 vcalc_sha256(0,mypriv.bytes,tmp256.bytes,32);
169 mypriv.bytes[0] &= 0xf8, mypriv.bytes[31] &= 0x7f, mypriv.bytes[31] |= 0x40;
170 mypub = curve25519(mypriv,curve25519_basepoint9());
171
91f21771 172 ssecret = curve25519(mypriv,txidpub);
173 ssecret2 = curve25519(txidpriv,mypub);
d176d2df 174 if ( memcmp(ssecret.bytes,ssecret2.bytes,32) == 0 )
8138fad2 175 {
ae748eaf 176 vcalc_sha256(0,(uint8_t *)&_entropy,ssecret.bytes,32);
177 vcalc_sha256(0,(uint8_t *)&_hentropy,_entropy,32);
dfe4c146 178 endiancpy((uint8_t *)&entropy,_entropy,32);
179 endiancpy((uint8_t *)&hentropy,_hentropy,32);
840a96ca 180 }
181 else
182 {
183 for (i=0; i<32; i++)
774b8b44 184 fprintf(stderr,"%02x",ssecret.bytes[i]);
840a96ca 185 fprintf(stderr," ssecret\n");
186 for (i=0; i<32; i++)
ac9816bb 187 fprintf(stderr,"%02x",ssecret2.bytes[i]);
840a96ca 188 fprintf(stderr," ssecret2 dont match\n");
189 }
8138fad2 190 return(hentropy);
191}
192
9025093e 193uint64_t DiceCalc(int64_t bet,int64_t odds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks,uint256 houseentropy,uint256 bettorentropy)
10078e85 194{
b52f7685 195 uint8_t buf[64],_house[32],_bettor[32]; uint64_t winnings; arith_uint256 house,bettor; char str[65],str2[65];
98c6e2e1 196 if ( odds < 10000 )
10078e85 197 return(0);
98c6e2e1 198 else odds -= 10000;
be7a410a 199 if ( bet < minbet || bet > maxbet || odds > maxodds )
200 {
201 fprintf(stderr,"bet size violation %.8f\n",(double)bet/COIN);
202 return(0);
203 }
204 endiancpy(buf,(uint8_t *)&houseentropy,32);
205 endiancpy(&buf[32],(uint8_t *)&bettorentropy,32);
206 vcalc_sha256(0,(uint8_t *)&_house,buf,64);
208f0e7a 207 endiancpy((uint8_t *)&house,_house,32);
be7a410a 208
209 endiancpy(buf,(uint8_t *)&bettorentropy,32);
210 endiancpy(&buf[32],(uint8_t *)&houseentropy,32);
211 vcalc_sha256(0,(uint8_t *)&_house,buf,64);
208f0e7a 212 endiancpy((uint8_t *)&bettor,_bettor,32);
b52f7685 213 if ( odds > 1 )
214 bettor = (bettor / arith_uint256(odds));
215 if ( bettor >= house )
216 winnings = bet * odds;
217 else winnings = 0;
d4c504f0 218 fprintf(stderr,"winnings %.8f bet %.8f at odds %d:1 %s vs %s\n",(double)winnings/COIN,(double)bet/COIN,(int32_t)odds,uint256_str(str,*(uint256 *)&house),uint256_str(str2,*(uint256 *)&bettor));
219 return(winnings);
10078e85 220}
221
9025093e 222CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
10078e85 223{
224 CScript opret; uint8_t evalcode = EVAL_DICE;
9025093e 225 opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << timeoutblocks);
10078e85 226 return(opret);
227}
228
9025093e 229uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks)
10078e85 230{
231 std::vector<uint8_t> vopret; uint8_t *script,e,f;
232 GetOpReturnData(scriptPubKey, vopret);
233 script = (uint8_t *)vopret.data();
9025093e 234 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 )
10078e85 235 {
236 if ( e == EVAL_DICE && f == 'F' )
237 return(f);
238 }
239 return(0);
240}
241
afef48c0 242CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid,uint256 hash,uint256 proof)
10078e85 243{
244 CScript opret; uint8_t evalcode = EVAL_DICE;
afef48c0 245 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid << hash << proof);
10078e85 246 return(opret);
247}
248
54519f69 249uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid,uint256 &hash,uint256 &proof)
10078e85 250{
9025093e 251 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,timeoutblocks;
753a6f92 252 GetOpReturnData(scriptPubKey,vopret);
10078e85 253 if ( vopret.size() > 2 )
254 {
255 script = (uint8_t *)vopret.data();
256 if ( script[0] == EVAL_DICE )
257 {
258 if ( script[1] == 'F' )
259 {
9025093e 260 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 )
10078e85 261 {
72362bbe 262 memset(&hash,0,32);
10078e85 263 fundingtxid = txid;
264 return('F');
265 } else fprintf(stderr,"unmarshal error for F\n");
266 }
54519f69 267 else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid; ss >> hash; ss >> proof) != 0 )
10078e85 268 {
02409974 269 if ( e == EVAL_DICE && (f == 'B' || f == 'W' || f == 'L' || f == 'T' || f == 'E') )
10078e85 270 return(f);
54519f69 271 else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f);
10078e85 272 }
273 } else fprintf(stderr,"script[0] %02x != EVAL_DICE\n",script[0]);
274 } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
275 return(0);
276}
cfea7a46 277
a03bb7fa 278uint256 DiceGetEntropy(CTransaction tx,uint8_t reffuncid)
279{
54519f69 280 uint256 hash,fundingtxid,proof; uint64_t sbits; int32_t numvouts;
281 if ( (numvouts= tx.vout.size()) > 0 && DecodeDiceOpRet(tx.GetHash(),tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof) == reffuncid )
a03bb7fa 282 return(hash);
283 else return(zeroid);
284}
285
cfea7a46 286uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
287{
288 char destaddr[64];
289 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
290 {
291 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
292 return(tx.vout[v].nValue);
293 }
294 return(0);
295}
296
4d2b7323 297int64_t DiceAmounts(uint64_t &inputs,uint64_t &outputs,struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
cfea7a46 298{
4d2b7323 299 CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t assetoshis;
cfea7a46 300 numvins = tx.vin.size();
301 numvouts = tx.vout.size();
302 for (i=0; i<numvins; i++)
303 {
cfea7a46 304 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
305 {
cfea7a46 306 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
10078e85 307 return eval->Invalid("always should find vin, but didnt");
cfea7a46 308 else
309 {
cfea7a46 310 if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
311 inputs += assetoshis;
312 }
313 }
314 }
315 for (i=0; i<numvouts; i++)
316 {
317 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
318 if ( (assetoshis= IsDicevout(cp,tx,i)) != 0 )
319 outputs += assetoshis;
320 }
4d2b7323 321 return(inputs - outputs);
cfea7a46 322}
323
1c87477b 324bool DiceIsmine(const CScript scriptPubKey)
325{
326 char destaddr[64],myaddr[64];
327 Getscriptaddress(destaddr,scriptPubKey);
ca05cbaa 328 Getscriptaddress(myaddr,CScript() << Mypubkey() << OP_CHECKSIG);
1c87477b 329 return(strcmp(destaddr,myaddr) == 0);
330}
331
aec296a5 332int32_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)
753a6f92 333{
aec296a5 334 uint64_t vinsbits,winnings; uint256 vinproof,vinfundingtxid,hentropy,hentropy2; uint8_t funcid;
753a6f92 335 //char str[65],str2[65];
4d2b7323 336 if ( DiceIsmine(vinTx.vout[1].scriptPubKey) != 0 && vinTx.vout.size() > 0 && vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 )
753a6f92 337 {
4d2b7323 338 if ( ((funcid= DecodeDiceOpRet(txid,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,hentropy,vinproof)) == 'E' || funcid == 'W' || funcid == 'L') && sbits == vinsbits && fundingtxid == vinfundingtxid )
753a6f92 339 {
340 hentropy2 = DiceHashEntropy(entropy,vinTx.vin[0].prevout.hash);
341 if ( hentropy == hentropy2 )
342 {
343 winnings = DiceCalc(tx.vout[1].nValue,tx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,entropy,bettorentropy);
344 //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);
345 if ( winnings == 0 )
346 {
347 // queue 'L' losing tx
348 return(-1);
349 }
350 else
351 {
352 // queue 'W' winning tx
353 return(1);
354 }
355 }
356 }
357 }
358 return(0);
359}
360
4d2b7323 361bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks)
cfea7a46 362{
4d2b7323 363 return(false);
364}
365
366bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
367{
368 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];
cfea7a46 369 numvins = tx.vin.size();
370 numvouts = tx.vout.size();
371 preventCCvins = preventCCvouts = -1;
372 if ( numvouts < 1 )
373 return eval->Invalid("no vouts");
374 else
375 {
10078e85 376 txid = tx.GetHash();
54519f69 377 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
cfea7a46 378 {
10078e85 379 if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
380 return eval->Invalid("cant find fundingtxid");
9025093e 381 else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 'F' )
10078e85 382 return eval->Invalid("fundingTx not valid");
4d2b7323 383 fundingPubKey = fundingTx.vout[1].scriptPubKey;
10078e85 384 switch ( funcid )
cfea7a46 385 {
10078e85 386 case 'F':
387 //vins.*: normal inputs
388 //vout.0: CC vout for funding
389 //vout.1: normal marker vout for easy searching
390 //vout.2: normal change
7eb60411 391 //vout.n-1: opreturn 'F' sbits minbet maxbet maxodds timeoutblocks
10078e85 392 return eval->Invalid("unexpected DiceValidate for createfunding");
393 break;
4d2b7323 394 case 'E': // check sig of vin to match fundingtxid in the 'B' tx
10078e85 395 //vins.*: normal inputs
0d4cfd0b 396 //vout.0: CC vout for locked entropy funds
397 //vout.1: tag to owner address for entropy funds
398 //vout.2: normal change
28b947b8 399 //vout.n-1: opreturn 'E' sbits fundingtxid hentropy
400 return eval->Invalid("unexpected DiceValidate for addfunding entropy");
10078e85 401 break;
04cf9f60 402 case 'B':
28b947b8 403 //vin.0: entropy txid from house
404 //vins.1+: normal inputs
0d4cfd0b 405 //vout.0: CC vout for locked entropy
28b947b8 406 //vout.1: CC vout for locked bet
98c6e2e1 407 //vout.2: tag for bettor's address (txfee + odds)
28b947b8 408 //vout.3: change
409 //vout.n-1: opreturn 'B' sbits fundingtxid entropy
4d2b7323 410 preventCCvouts = 2;
411 preventCCvins = 1;
412 if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
413 return eval->Invalid("vin.0 is normal for bet");
414 else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
415 return eval->Invalid("vout.0 is normal for bet");
416 else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
417 return eval->Invalid("vout.1 is normal for bet");
418 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
419 return eval->Invalid("always should find vin.0, but didnt for bet");
420 else if ( vinTx.vout[1].scriptPubKey != fundingPubKey )
421 return eval->Invalid("entropy tx not fundingPubKey for bet");
422 else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,vinTx.vout[tx.vin[0].prevout.n].nValue) == 0 )
423 return eval->Invalid("vout[0] != entropy nValue for bet");
424 else if ( ConstrainVout(tx.vout[1],1,cp->unspendableCCaddr,0) == 0 )
425 return eval->Invalid("vout[1] constrain violation for bet");
426 else if ( tx.vout[2].nValue >= txfee+maxodds || tx.vout[2].nValue < txfee )
427 return eval->Invalid("vout[2] nValue violation for bet");
428 else if ( eval->GetTxUnconfirmed(vinTx.vin[0].prevout.hash,vinofvinTx,hashBlock) == 0 )
429 return eval->Invalid("always should find vinofvin.0, but didnt for bet");
430 else if ( vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey != fundingPubKey )
431 return eval->Invalid("vin0 of entropy tx not fundingPubKey for bet");
432 else if ( vinTx.vout[vinTx.vin[0].prevout.n].nValue != tx.vout[0].nValue )
433 return eval->Invalid("vout.0 nValue != entropy nValue for bet");
aec296a5 434 if ( (iswin= DiceIsWinner(entropy,txid,tx,vinTx,hash,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
1c87477b 435 {
4d2b7323 436 // will only happen for fundingPubKey
fb89b441 437 DiceQueue(iswin,sbits,fundingtxid,txid);
1c87477b 438 }
10078e85 439 break;
5d3d3a87 440 case 'L':
5d3d3a87 441 case 'W':
02409974 442 case 'T':
7eb60411 443 //vin.0: betTx CC vout.0 entropy from bet
444 //vin.1: betTx CC vout.1 bet amount from bet
02409974 445 //vin.2+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T'
7eb60411 446 //vout.1: tag to owner address for entropy funds
4d2b7323 447 preventCCvouts = 1;
448 DiceAmounts(inputs,outputs,cp,eval,tx);
449 if ( IsCCInput(tx.vin[0].scriptSig) == 0 || IsCCInput(tx.vin[1].scriptSig) == 0 )
450 return eval->Invalid("vin0 or vin1 normal vin for bet");
451 else if ( tx.vin[0].prevout.hash != tx.vin[1].prevout.hash )
452 return eval->Invalid("vin0 != vin1 prevout.hash for bet");
453 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
454 return eval->Invalid("always should find vin.0, but didnt for wlt");
455 else if ( vinTx.vout.size() < 3 || DecodeDiceOpRet(tx.vin[0].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,vinhentropy,vinproof) != 'B' )
456 return eval->Invalid("not betTx for vin0/1 for wlt");
457 else if ( sbits != vinsbits || fundingtxid != vinfundingtxid )
458 return eval->Invalid("sbits or fundingtxid mismatch for wlt");
459 else if ( fundingPubKey != tx.vout[1].scriptPubKey )
460 return eval->Invalid("tx.vout[1] != fundingPubKey for wlt");
461 if ( funcid == 'L' )
10078e85 462 {
4d2b7323 463 //vout.0: funding CC to entropy owner
464 //vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof
465 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,inputs-txfee) == 0 )
466 return eval->Invalid("vout[0] != inputs-txfee for loss");
467 iswin = -1;
10078e85 468 }
4d2b7323 469 else
470 {
471 //vout.0: funding CC change to entropy owner
472 //vout.2: normal output to bettor's address
473 //vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
474 odds = vinTx.vout[2].nValue - txfee;
475 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
476 return eval->Invalid("vout[0] != inputs-txfee for win/timeout");
477 else if ( tx.vout[2].scriptPubKey != vinTx.vout[2].scriptPubKey )
478 return eval->Invalid("vout[2] scriptPubKey mismatch for win/timeout");
479 else if ( tx.vout[2].nValue != odds*vinTx.vout[1].nValue )
480 return eval->Invalid("vout[2] payut mismatch for win/timeout");
4e12f16c 481 else if ( inputs != outputs+tx.vout[2].nValue-txfee )
4d2b7323 482 return eval->Invalid("CC funds mismatch for win/timeout");
483 iswin = (funcid == 'W');
484 }
485 if ( iswin != 0 )
486 {
487 winnings = DiceCalc(vinTx.vout[1].nValue,vinTx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,proof,hash);
488 if ( (winnings == 0 && iswin > 0) || (winnings > 0 && iswin < 0) )
489 return eval->Invalid("DiceCalc mismatch for win/loss");
490 }
491 else if ( DiceVerifyTimeout(vinTx,timeoutblocks) == 0 )
492 return eval->Invalid("invalid timeout claim for timeout");
10078e85 493 break;
cfea7a46 494 }
495 }
10078e85 496 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
cfea7a46 497 }
10078e85 498 return(true);
cfea7a46 499}
cfea7a46 500
4d2b7323 501uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
cfea7a46 502{
54519f69 503 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;
cfea7a46 504 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
505 GetCCaddress(cp,coinaddr,pk);
506 SetCCunspents(unspentOutputs,coinaddr);
507 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
508 {
509 txid = it->first.txhash;
10078e85 510 vout = (int32_t)it->first.index;
93ac96fa 511 if ( it->second.satoshis < 1000000 )
c2342f7b 512 continue;
10078e85 513 fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
514 for (j=0; j<mtx.vin.size(); j++)
515 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
516 break;
517 if ( j != mtx.vin.size() )
518 continue;
519 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
cfea7a46 520 {
54519f69 521 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
cfea7a46 522 {
4d2b7323 523 if ( funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T' )
10078e85 524 {
4d2b7323 525 if ( total != 0 && maxinputs != 0 )
526 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
527 totalinputs += it->second.satoshis;
528 n++;
529 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
530 break;
10078e85 531 }
10078e85 532 } else fprintf(stderr,"null funcid\n");
cfea7a46 533 }
534 }
535 return(totalinputs);
536}
537
4d2b7323 538uint64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey dicepk,uint256 reffundingtxid)
10078e85 539{
4d2b7323 540 char coinaddr[64]; 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;
10078e85 541 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
a1b43551 542 if ( GetTransaction(reffundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) != 0 )
543 {
544 fundingPubKey = tx.vout[1].scriptPubKey;
545 } else return(0);
4d2b7323 546 GetCCaddress(cp,coinaddr,dicepk);
10078e85 547 SetCCunspents(unspentOutputs,coinaddr);
04cf9f60 548 entropyval = 0;
10078e85 549 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
550 {
551 txid = it->first.txhash;
552 vout = (int32_t)it->first.index;
553 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
554 {
4d2b7323 555 //char str[65],str2[65];
54519f69 556 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
10078e85 557 {
558 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
559 {
4d2b7323 560 if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 10000 && (funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T') )
04cf9f60 561 {
4d2b7323 562 if ( funcid != 'F' && funcid != 'T' )
14debc6d 563 {
4d2b7323 564 n++;
14debc6d 565 fprintf(stderr,"(%c %.8f) ",funcid,(double)nValue/COIN);
566 }
10078e85 567 totalinputs += nValue;
14debc6d 568 if ( first == 0 && (funcid == 'E' || funcid == 'W' || funcid == 'L') )
04cf9f60 569 {
14debc6d 570 if ( fundingPubKey == tx.vout[1].scriptPubKey )
4d2b7323 571 {
14debc6d 572 if ( funcid == 'E' )
4d2b7323 573 {
b13e77bb 574 if ( tx.vin[0].prevout.n != 0 || GetTransaction(tx.vin[0].prevout.hash,vinTx,hashBlock,false) == 0 || vinTx.vout.size() < 2 )
8eef6813 575 {
576 fprintf(stderr,"cant find entropy tx or vin0prev %d\n",tx.vin[0].prevout.n);
577 continue;
578 }
579 if ( vinTx.vout[1].scriptPubKey != fundingPubKey )
14debc6d 580 {
385f6db0 581 uint8_t *ptr0,*ptr1; int32_t i;
6138f598 582 ptr0 = (uint8_t *)vinTx.vout[1].scriptPubKey.data();
385f6db0 583 ptr1 = (uint8_t *)fundingPubKey.data();
584 for (i=0; i<tx.vout[1].scriptPubKey.size(); i++)
585 fprintf(stderr,"%02x",ptr0[i]);
586 fprintf(stderr," script vs ");
587 for (i=0; i<fundingPubKey.size(); i++)
588 fprintf(stderr,"%02x",ptr1[i]);
6138f598 589 fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch\n",funcid,tx.vin[0].prevout.n);
14debc6d 590 continue;
591 }
4d2b7323 592 }
14debc6d 593 entropytxid = txid;
594 entropyval = tx.vout[0].nValue;
595 first = 1;
04a4df80 596 }
04cf9f60 597 }
d4c504f0 598 } //else fprintf(stderr,"%c refsbits.%llx sbits.%llx nValue %.8f\n",funcid,(long long)refsbits,(long long)sbits,(double)nValue/COIN);
599 } //else fprintf(stderr,"else case funcid (%c) %d %s vs %s\n",funcid,funcid,uint256_str(str,reffundingtxid),uint256_str(str2,fundingtxid));
06811319 600 } //else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
10078e85 601 }
602 }
4d2b7323 603 fprintf(stderr,"numentropy tx %d: %.8f\n",n,(double)totalinputs/COIN);
10078e85 604 return(totalinputs);
605}
606
aec296a5 607bool 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)
10078e85 608{
609 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
610 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
611 GetCCaddress(cp,CCaddr,dicepk);
3c3451b8 612 SetCCtxids(txids,cp->normaladdr);
aec296a5 613 if ( fundingtxid != zeroid ) // avoid scan unless creating new funding plan
614 {
83da810c 615 if ( GetTransaction(fundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
aec296a5 616 {
617 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' && sbits == refsbits )
618 {
619 fundingPubKey = tx.vout[1].scriptPubKey;
620 return(true);
621 }
622 }
623 return(false);
624 }
10078e85 625 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
626 {
627 //int height = it->first.blockHeight;
628 txid = it->first.txhash;
a03bb7fa 629 if ( fundingtxid != zeroid && txid != fundingtxid )
630 continue;
10078e85 631 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
632 {
9025093e 633 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' )
10078e85 634 {
635 if ( sbits == refsbits )
a03bb7fa 636 {
aec296a5 637 fundingPubKey = tx.vout[1].scriptPubKey;
a03bb7fa 638 fundingtxid = txid;
10078e85 639 return(true);
a03bb7fa 640 }
10078e85 641 }
642 }
643 }
644 return(false);
645}
646
46a40047 647struct 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)
a03bb7fa 648{
28500c30 649 struct CCcontract_info *cp; int32_t cmpflag;
a03bb7fa 650 cp = CCinit(C,EVAL_DICE);
651 if ( txfee == 0 )
652 txfee = 10000;
653 mypk = pubkey2pk(Mypubkey());
654 dicepk = GetUnspendable(cp,0);
655 sbits = stringbits(planstr);
656 if ( reffundingtxid == zeroid )
657 cmpflag = 0;
658 else cmpflag = 1;
28500c30 659 if ( DicePlanExists(fundingPubKey,reffundingtxid,cp,sbits,dicepk,minbet,maxbet,maxodds,timeoutblocks) != cmpflag )
a03bb7fa 660 {
97b0bc3a 661 fprintf(stderr,"Dice plan (%s) already exists cmpflag.%d\n",planstr,cmpflag);
a03bb7fa 662 return(0);
663 }
664 return(cp);
665}
666
10078e85 667UniValue DiceInfo(uint256 diceid)
668{
f516779c 669 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;
10078e85 670 if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 )
671 {
672 fprintf(stderr,"cant find fundingtxid\n");
673 result.push_back(Pair("error","cant find fundingtxid"));
674 return(result);
675 }
9025093e 676 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 0 )
10078e85 677 {
678 fprintf(stderr,"fundingtxid isnt dice creation txid\n");
679 result.push_back(Pair("error","fundingtxid isnt dice creation txid"));
680 return(result);
681 }
682 result.push_back(Pair("result","success"));
683 result.push_back(Pair("fundingtxid",uint256_str(str,diceid)));
684 unstringbits(str,sbits);
685 result.push_back(Pair("name",str));
686 result.push_back(Pair("sbits",sbits));
d0d96ab0 687 sprintf(numstr,"%.8f",(double)minbet/COIN);
688 result.push_back(Pair("minbet",numstr));
689 sprintf(numstr,"%.8f",(double)maxbet/COIN);
690 result.push_back(Pair("maxbet",numstr));
691 result.push_back(Pair("maxodds",maxodds));
9025093e 692 result.push_back(Pair("timeoutblocks",timeoutblocks));
f516779c 693 cp = CCinit(&C,EVAL_DICE);
694 dicepk = GetUnspendable(cp,0);
688d3ac4 695 funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,diceid);
f516779c 696 sprintf(numstr,"%.8f",(double)funding/COIN);
10078e85 697 result.push_back(Pair("funding",numstr));
698 return(result);
699}
700
701UniValue DiceList()
cfea7a46 702{
9025093e 703 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];
10078e85 704 cp = CCinit(&C,EVAL_DICE);
705 SetCCtxids(addressIndex,cp->normaladdr);
706 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
707 {
708 txid = it->first.txhash;
709 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
710 {
9025093e 711 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 0 )
10078e85 712 {
713 result.push_back(uint256_str(str,txid));
714 }
715 }
716 }
717 return(result);
718}
719
9025093e 720std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
05177cfb 721{
aec296a5 722 CMutableTransaction mtx; uint256 zero; CScript fundingPubKey; CPubKey mypk,dicepk; int64_t a,b,c,d; uint64_t sbits; struct CCcontract_info *cp,C;
9025093e 723 if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || timeoutblocks < 0 || timeoutblocks > 1440 )
05177cfb 724 {
725 fprintf(stderr,"negative parameter error\n");
726 return(0);
727 }
aec296a5 728 memset(&zero,0,sizeof(zero));
729 if ( (cp= Diceinit(fundingPubKey,zero,&C,planstr,txfee,mypk,dicepk,sbits,a,b,c,d)) == 0 )
05177cfb 730 return(0);
32e3be87 731 if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 )
10078e85 732 {
733 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk));
32e3be87 734 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
10078e85 735 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG));
9025093e 736 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,timeoutblocks)));
10078e85 737 }
738 fprintf(stderr,"cant find enough inputs\n");
739 return(0);
740}
741
742std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
743{
aec296a5 744 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;
10078e85 745 if ( amount < 0 )
746 {
747 fprintf(stderr,"negative parameter error\n");
748 return(0);
749 }
aec296a5 750 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
10078e85 751 return(0);
aec296a5 752 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
d3cc1ec1 753 if ( 1 )
792cef06 754 {
755 uint8_t *ptr0,*ptr1; int32_t i;
756 ptr0 = (uint8_t *)scriptPubKey.data();
757 ptr1 = (uint8_t *)fundingPubKey.data();
758 for (i=0; i<35; i++)
759 fprintf(stderr,"%02x",ptr0[i]);
760 fprintf(stderr," script vs ");
761 for (i=0; i<35; i++)
762 fprintf(stderr,"%02x",ptr1[i]);
763 fprintf(stderr," funding\n");
764 }
aec296a5 765 if ( scriptPubKey == fundingPubKey )
10078e85 766 {
aec296a5 767 if ( AddNormalinputs(mtx,mypk,amount+2*txfee,64) > 0 )
768 {
769 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
770 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk));
7377f6ea 771 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
aec296a5 772 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('E',sbits,fundingtxid,hentropy,zeroid)));
773 } else fprintf(stderr,"cant find enough inputs\n");
774 } else fprintf(stderr,"only fund creator can add more funds (entropy)\n");
cfea7a46 775 return(0);
776}
777
7347a801 778std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds)
5d3d3a87 779{
aec296a5 780 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;
7347a801 781 if ( bet < 0 || odds < 1 )
5d3d3a87 782 {
783 fprintf(stderr,"negative parameter error\n");
784 return(0);
785 }
aec296a5 786 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
7347a801 787 return(0);
788 if ( bet < minbet || bet > maxbet || odds > maxodds )
789 {
790 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);
791 return(0);
792 }
7eb60411 793 if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid)) >= 2*bet*odds+txfee && entropyval != 0 )
7347a801 794 {
795 mtx.vin.push_back(CTxIn(entropytxid,0,CScript()));
796 if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 )
797 {
798 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
799 mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk));
800 mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk));
801 mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
afef48c0 802 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('B',sbits,fundingtxid,entropy,zeroid)));
7347a801 803 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN);
804 }
805 if ( entropyval == 0 && funding != 0 )
806 fprintf(stderr,"cant find dice entropy inputs\n");
807 else fprintf(stderr,"cant find dice inputs\n");
808 return(0);
809}
810
cfdc3770 811std::string DiceWinLoseTimeout(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout)
7347a801 812{
4d2b7323 813 CMutableTransaction mtx; CScript scriptPubKey,fundingPubKey; CTransaction betTx,entropyTx; uint256 hentropyproof,entropytxid,hashBlock,bettorentropy,entropy,hentropy; CPubKey mypk,dicepk; 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;
cfdc3770 814 *resultp = 0;
aec296a5 815 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
113adfd4 816 return("0");
aec296a5 817 if ( winlosetimeout != 0 )
818 {
819 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
820 if ( scriptPubKey != fundingPubKey )
821 {
822 fprintf(stderr,"only dice fund creator can submit winner or loser\n");
113adfd4 823 return("0");
aec296a5 824 }
825 }
a03bb7fa 826 if ( GetTransaction(bettxid,betTx,hashBlock,false) != 0 && GetTransaction(betTx.vin[0].prevout.hash,entropyTx,hashBlock,false) != 0 )
5d3d3a87 827 {
a03bb7fa 828 bettorentropy = DiceGetEntropy(betTx,'B');
4d2b7323 829 if ( winlosetimeout == 0 || (iswin= DiceIsWinner(hentropyproof,bettxid,betTx,entropyTx,bettorentropy,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
a03bb7fa 830 {
02409974 831 if ( iswin == winlosetimeout )
a03bb7fa 832 {
7eb60411 833 fprintf(stderr,"iswin.%d matches\n",iswin);
834 mtx.vin.push_back(CTxIn(bettxid,0,CScript()));
835 mtx.vin.push_back(CTxIn(bettxid,1,CScript()));
a03bb7fa 836 if ( iswin == 0 )
7eb60411 837 {
02409974 838 funcid = 'T';
4d2b7323 839 if ( DiceVerifyTimeout(betTx,timeoutblocks) == 0 ) // hasnt timed out yet
840 {
841 fprintf(stderr,"timeout is not supported yet\n");
842 return(0);
843 }
844 else
845 {
846 hentropy = hentropyproof = zeroid;
847 iswin = 1;
848 }
7eb60411 849 }
4d2b7323 850 if ( iswin > 0 )
7eb60411 851 {
a03bb7fa 852 funcid = 'W';
7eb60411 853 odds = (betTx.vout[2].nValue - txfee);
854 if ( odds < 1 || odds > maxodds )
855 {
856 fprintf(stderr,"illegal odds.%d vs maxodds.%d\n",(int32_t)odds,(int32_t)maxodds);
113adfd4 857 return("0");
7eb60411 858 }
859 CCchange = betTx.vout[0].nValue;
860 fundsneeded = 2*txfee + (odds-1)*betTx.vout[1].nValue;
4d2b7323 861 if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60)) > 0 )
7eb60411 862 {
863 if ( inputs > fundsneeded+txfee )
864 CCchange += (inputs - (fundsneeded+txfee));
865 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk));
04a4df80 866 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
7eb60411 867 mtx.vout.push_back(CTxOut(odds * betTx.vout[1].nValue,betTx.vout[2].scriptPubKey));
868 }
869 else
870 {
871 fprintf(stderr,"not enough inputs for %.8f\n",(double)fundsneeded/COIN);
113adfd4 872 return("0");
7eb60411 873 }
874 }
875 else
a03bb7fa 876 {
7eb60411 877 funcid = 'L';
878 mtx.vout.push_back(MakeCC1vout(cp->evalcode,betTx.vout[0].nValue + betTx.vout[1].nValue - txfee,dicepk));
04a4df80 879 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
7eb60411 880 }
4d2b7323 881 if ( winlosetimeout != 0 )
882 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
cfdc3770 883 *resultp = 1;
afef48c0 884 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet(funcid,sbits,fundingtxid,hentropy,hentropyproof)));
e0ea3b3e 885 } else fprintf(stderr,"iswin.%d does not match.%d\n",iswin,winlosetimeout);
113adfd4 886 } else return("0");
a03bb7fa 887 }
113adfd4 888 return("0");
5d3d3a87 889}
890
This page took 0.182148 seconds and 4 git commands to generate.