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