]> Git Repo - VerusCoin.git/blame - src/cc/dice.cpp
-print
[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 {
ef979a50 144 //fprintf(stderr,"DiceQueue.%d\n",iswin);
7377f6ea 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 }
ef979a50 190 //char str[65],str2[65];
191 //fprintf(stderr,"generated house hentropy.%s <- entropy.%s\n",uint256_str(str,hentropy),uint256_str(str2,entropy));
8138fad2 192 return(hentropy);
193}
194
9025093e 195uint64_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 196{
b52f7685 197 uint8_t buf[64],_house[32],_bettor[32]; uint64_t winnings; arith_uint256 house,bettor; char str[65],str2[65];
98c6e2e1 198 if ( odds < 10000 )
10078e85 199 return(0);
98c6e2e1 200 else odds -= 10000;
be7a410a 201 if ( bet < minbet || bet > maxbet || odds > maxodds )
202 {
203 fprintf(stderr,"bet size violation %.8f\n",(double)bet/COIN);
204 return(0);
205 }
ef979a50 206 //fprintf(stderr,"calc house entropy %s vs bettor %s\n",uint256_str(str,houseentropy),uint256_str(str2,bettorentropy));
aa760cb8 207
be7a410a 208 endiancpy(buf,(uint8_t *)&houseentropy,32);
209 endiancpy(&buf[32],(uint8_t *)&bettorentropy,32);
210 vcalc_sha256(0,(uint8_t *)&_house,buf,64);
208f0e7a 211 endiancpy((uint8_t *)&house,_house,32);
be7a410a 212
213 endiancpy(buf,(uint8_t *)&bettorentropy,32);
214 endiancpy(&buf[32],(uint8_t *)&houseentropy,32);
36dcc2e6 215 vcalc_sha256(0,(uint8_t *)&_bettor,buf,64);
208f0e7a 216 endiancpy((uint8_t *)&bettor,_bettor,32);
b52f7685 217 if ( odds > 1 )
218 bettor = (bettor / arith_uint256(odds));
219 if ( bettor >= house )
220 winnings = bet * odds;
221 else winnings = 0;
d4c504f0 222 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));
223 return(winnings);
10078e85 224}
225
9025093e 226CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
10078e85 227{
228 CScript opret; uint8_t evalcode = EVAL_DICE;
9025093e 229 opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << timeoutblocks);
10078e85 230 return(opret);
231}
232
9025093e 233uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks)
10078e85 234{
235 std::vector<uint8_t> vopret; uint8_t *script,e,f;
236 GetOpReturnData(scriptPubKey, vopret);
237 script = (uint8_t *)vopret.data();
9025093e 238 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 )
10078e85 239 {
240 if ( e == EVAL_DICE && f == 'F' )
241 return(f);
242 }
243 return(0);
244}
245
afef48c0 246CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid,uint256 hash,uint256 proof)
10078e85 247{
248 CScript opret; uint8_t evalcode = EVAL_DICE;
afef48c0 249 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid << hash << proof);
10078e85 250 return(opret);
251}
252
54519f69 253uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid,uint256 &hash,uint256 &proof)
10078e85 254{
9025093e 255 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,timeoutblocks;
753a6f92 256 GetOpReturnData(scriptPubKey,vopret);
10078e85 257 if ( vopret.size() > 2 )
258 {
259 script = (uint8_t *)vopret.data();
260 if ( script[0] == EVAL_DICE )
261 {
262 if ( script[1] == 'F' )
263 {
9025093e 264 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 )
10078e85 265 {
72362bbe 266 memset(&hash,0,32);
10078e85 267 fundingtxid = txid;
268 return('F');
269 } else fprintf(stderr,"unmarshal error for F\n");
270 }
54519f69 271 else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid; ss >> hash; ss >> proof) != 0 )
10078e85 272 {
02409974 273 if ( e == EVAL_DICE && (f == 'B' || f == 'W' || f == 'L' || f == 'T' || f == 'E') )
10078e85 274 return(f);
54519f69 275 else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f);
10078e85 276 }
277 } else fprintf(stderr,"script[0] %02x != EVAL_DICE\n",script[0]);
278 } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
279 return(0);
280}
cfea7a46 281
a03bb7fa 282uint256 DiceGetEntropy(CTransaction tx,uint8_t reffuncid)
283{
54519f69 284 uint256 hash,fundingtxid,proof; uint64_t sbits; int32_t numvouts;
285 if ( (numvouts= tx.vout.size()) > 0 && DecodeDiceOpRet(tx.GetHash(),tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof) == reffuncid )
a03bb7fa 286 return(hash);
287 else return(zeroid);
288}
289
cfea7a46 290uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
291{
292 char destaddr[64];
293 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
294 {
295 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
296 return(tx.vout[v].nValue);
297 }
298 return(0);
299}
300
4d2b7323 301int64_t DiceAmounts(uint64_t &inputs,uint64_t &outputs,struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
cfea7a46 302{
4d2b7323 303 CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t assetoshis;
cfea7a46 304 numvins = tx.vin.size();
305 numvouts = tx.vout.size();
60301f5e 306 inputs = outputs = 0;
cfea7a46 307 for (i=0; i<numvins; i++)
308 {
cfea7a46 309 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
310 {
cfea7a46 311 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
10078e85 312 return eval->Invalid("always should find vin, but didnt");
cfea7a46 313 else
314 {
cfea7a46 315 if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
316 inputs += assetoshis;
317 }
318 }
319 }
320 for (i=0; i<numvouts; i++)
321 {
322 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
323 if ( (assetoshis= IsDicevout(cp,tx,i)) != 0 )
324 outputs += assetoshis;
325 }
4d2b7323 326 return(inputs - outputs);
cfea7a46 327}
328
1c87477b 329bool DiceIsmine(const CScript scriptPubKey)
330{
331 char destaddr[64],myaddr[64];
332 Getscriptaddress(destaddr,scriptPubKey);
ca05cbaa 333 Getscriptaddress(myaddr,CScript() << Mypubkey() << OP_CHECKSIG);
1c87477b 334 return(strcmp(destaddr,myaddr) == 0);
335}
336
aec296a5 337int32_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 338{
aec296a5 339 uint64_t vinsbits,winnings; uint256 vinproof,vinfundingtxid,hentropy,hentropy2; uint8_t funcid;
753a6f92 340 //char str[65],str2[65];
4d2b7323 341 if ( DiceIsmine(vinTx.vout[1].scriptPubKey) != 0 && vinTx.vout.size() > 0 && vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 )
753a6f92 342 {
4d2b7323 343 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 344 {
345 hentropy2 = DiceHashEntropy(entropy,vinTx.vin[0].prevout.hash);
346 if ( hentropy == hentropy2 )
347 {
348 winnings = DiceCalc(tx.vout[1].nValue,tx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,entropy,bettorentropy);
349 //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);
350 if ( winnings == 0 )
351 {
352 // queue 'L' losing tx
353 return(-1);
354 }
355 else
356 {
357 // queue 'W' winning tx
358 return(1);
359 }
360 }
361 }
362 }
363 return(0);
364}
365
4d2b7323 366bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks)
cfea7a46 367{
4d2b7323 368 return(false);
369}
370
371bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx)
372{
373 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 374 numvins = tx.vin.size();
375 numvouts = tx.vout.size();
376 preventCCvins = preventCCvouts = -1;
377 if ( numvouts < 1 )
378 return eval->Invalid("no vouts");
379 else
380 {
10078e85 381 txid = tx.GetHash();
54519f69 382 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
cfea7a46 383 {
10078e85 384 if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
385 return eval->Invalid("cant find fundingtxid");
9025093e 386 else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 'F' )
10078e85 387 return eval->Invalid("fundingTx not valid");
4d2b7323 388 fundingPubKey = fundingTx.vout[1].scriptPubKey;
10078e85 389 switch ( funcid )
cfea7a46 390 {
10078e85 391 case 'F':
392 //vins.*: normal inputs
393 //vout.0: CC vout for funding
394 //vout.1: normal marker vout for easy searching
395 //vout.2: normal change
7eb60411 396 //vout.n-1: opreturn 'F' sbits minbet maxbet maxodds timeoutblocks
10078e85 397 return eval->Invalid("unexpected DiceValidate for createfunding");
398 break;
4d2b7323 399 case 'E': // check sig of vin to match fundingtxid in the 'B' tx
10078e85 400 //vins.*: normal inputs
0d4cfd0b 401 //vout.0: CC vout for locked entropy funds
402 //vout.1: tag to owner address for entropy funds
403 //vout.2: normal change
28b947b8 404 //vout.n-1: opreturn 'E' sbits fundingtxid hentropy
405 return eval->Invalid("unexpected DiceValidate for addfunding entropy");
10078e85 406 break;
04cf9f60 407 case 'B':
28b947b8 408 //vin.0: entropy txid from house
409 //vins.1+: normal inputs
0d4cfd0b 410 //vout.0: CC vout for locked entropy
28b947b8 411 //vout.1: CC vout for locked bet
98c6e2e1 412 //vout.2: tag for bettor's address (txfee + odds)
28b947b8 413 //vout.3: change
414 //vout.n-1: opreturn 'B' sbits fundingtxid entropy
4d2b7323 415 preventCCvouts = 2;
416 preventCCvins = 1;
417 if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
418 return eval->Invalid("vin.0 is normal for bet");
419 else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
420 return eval->Invalid("vout.0 is normal for bet");
421 else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
422 return eval->Invalid("vout.1 is normal for bet");
423 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
424 return eval->Invalid("always should find vin.0, but didnt for bet");
425 else if ( vinTx.vout[1].scriptPubKey != fundingPubKey )
426 return eval->Invalid("entropy tx not fundingPubKey for bet");
427 else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,vinTx.vout[tx.vin[0].prevout.n].nValue) == 0 )
428 return eval->Invalid("vout[0] != entropy nValue for bet");
429 else if ( ConstrainVout(tx.vout[1],1,cp->unspendableCCaddr,0) == 0 )
430 return eval->Invalid("vout[1] constrain violation for bet");
431 else if ( tx.vout[2].nValue >= txfee+maxodds || tx.vout[2].nValue < txfee )
432 return eval->Invalid("vout[2] nValue violation for bet");
433 else if ( eval->GetTxUnconfirmed(vinTx.vin[0].prevout.hash,vinofvinTx,hashBlock) == 0 )
434 return eval->Invalid("always should find vinofvin.0, but didnt for bet");
435 else if ( vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey != fundingPubKey )
436 return eval->Invalid("vin0 of entropy tx not fundingPubKey for bet");
437 else if ( vinTx.vout[vinTx.vin[0].prevout.n].nValue != tx.vout[0].nValue )
438 return eval->Invalid("vout.0 nValue != entropy nValue for bet");
aec296a5 439 if ( (iswin= DiceIsWinner(entropy,txid,tx,vinTx,hash,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
1c87477b 440 {
4d2b7323 441 // will only happen for fundingPubKey
fb89b441 442 DiceQueue(iswin,sbits,fundingtxid,txid);
1c87477b 443 }
10078e85 444 break;
5d3d3a87 445 case 'L':
5d3d3a87 446 case 'W':
02409974 447 case 'T':
7eb60411 448 //vin.0: betTx CC vout.0 entropy from bet
449 //vin.1: betTx CC vout.1 bet amount from bet
02409974 450 //vin.2+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T'
7eb60411 451 //vout.1: tag to owner address for entropy funds
4d2b7323 452 preventCCvouts = 1;
453 DiceAmounts(inputs,outputs,cp,eval,tx);
454 if ( IsCCInput(tx.vin[0].scriptSig) == 0 || IsCCInput(tx.vin[1].scriptSig) == 0 )
455 return eval->Invalid("vin0 or vin1 normal vin for bet");
456 else if ( tx.vin[0].prevout.hash != tx.vin[1].prevout.hash )
457 return eval->Invalid("vin0 != vin1 prevout.hash for bet");
458 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
459 return eval->Invalid("always should find vin.0, but didnt for wlt");
460 else if ( vinTx.vout.size() < 3 || DecodeDiceOpRet(tx.vin[0].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,vinhentropy,vinproof) != 'B' )
461 return eval->Invalid("not betTx for vin0/1 for wlt");
462 else if ( sbits != vinsbits || fundingtxid != vinfundingtxid )
463 return eval->Invalid("sbits or fundingtxid mismatch for wlt");
464 else if ( fundingPubKey != tx.vout[1].scriptPubKey )
465 return eval->Invalid("tx.vout[1] != fundingPubKey for wlt");
466 if ( funcid == 'L' )
10078e85 467 {
4d2b7323 468 //vout.0: funding CC to entropy owner
469 //vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof
470 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,inputs-txfee) == 0 )
471 return eval->Invalid("vout[0] != inputs-txfee for loss");
472 iswin = -1;
10078e85 473 }
4d2b7323 474 else
475 {
476 //vout.0: funding CC change to entropy owner
477 //vout.2: normal output to bettor's address
478 //vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
479 odds = vinTx.vout[2].nValue - txfee;
480 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
481 return eval->Invalid("vout[0] != inputs-txfee for win/timeout");
482 else if ( tx.vout[2].scriptPubKey != vinTx.vout[2].scriptPubKey )
483 return eval->Invalid("vout[2] scriptPubKey mismatch for win/timeout");
484 else if ( tx.vout[2].nValue != odds*vinTx.vout[1].nValue )
485 return eval->Invalid("vout[2] payut mismatch for win/timeout");
3454564b 486 else if ( inputs != (outputs + tx.vout[2].nValue + 2*txfee) )
d2c1a2f2 487 {
488 fprintf(stderr,"inputs %.8f != outputs %.8f + 2 %.8f - txfee\n",(double)inputs/COIN,(double)outputs/COIN,(double)tx.vout[2].nValue/COIN);
4d2b7323 489 return eval->Invalid("CC funds mismatch for win/timeout");
d2c1a2f2 490 }
4d2b7323 491 iswin = (funcid == 'W');
492 }
493 if ( iswin != 0 )
494 {
ef979a50 495 //char str[65],str2[65];
53f6ead6 496 entropy = DiceGetEntropy(vinTx,'B');
e7479ef8 497 vcalc_sha256(0,(uint8_t *)&hash,(uint8_t *)&proof,32);
ef979a50 498 //fprintf(stderr,"calculated house hentropy.%s\n",uint256_str(str,hash));
499 //fprintf(stderr,"verify house entropy %s vs bettor %s\n",uint256_str(str,proof),uint256_str(str2,entropy));
53f6ead6 500 winnings = DiceCalc(vinTx.vout[1].nValue,vinTx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,proof,entropy);
4d2b7323 501 if ( (winnings == 0 && iswin > 0) || (winnings > 0 && iswin < 0) )
502 return eval->Invalid("DiceCalc mismatch for win/loss");
503 }
504 else if ( DiceVerifyTimeout(vinTx,timeoutblocks) == 0 )
505 return eval->Invalid("invalid timeout claim for timeout");
10078e85 506 break;
cfea7a46 507 }
508 }
10078e85 509 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
cfea7a46 510 }
10078e85 511 return(true);
cfea7a46 512}
cfea7a46 513
4d2b7323 514uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
cfea7a46 515{
54519f69 516 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 517 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
518 GetCCaddress(cp,coinaddr,pk);
519 SetCCunspents(unspentOutputs,coinaddr);
520 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
521 {
522 txid = it->first.txhash;
10078e85 523 vout = (int32_t)it->first.index;
93ac96fa 524 if ( it->second.satoshis < 1000000 )
c2342f7b 525 continue;
ef979a50 526 //fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
10078e85 527 for (j=0; j<mtx.vin.size(); j++)
528 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
529 break;
530 if ( j != mtx.vin.size() )
531 continue;
532 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
cfea7a46 533 {
54519f69 534 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
cfea7a46 535 {
4d2b7323 536 if ( funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T' )
10078e85 537 {
4d2b7323 538 if ( total != 0 && maxinputs != 0 )
539 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
540 totalinputs += it->second.satoshis;
541 n++;
542 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
543 break;
10078e85 544 }
10078e85 545 } else fprintf(stderr,"null funcid\n");
cfea7a46 546 }
547 }
548 return(totalinputs);
549}
550
4d2b7323 551uint64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey dicepk,uint256 reffundingtxid)
10078e85 552{
e9c75366 553 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;
10078e85 554 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
a1b43551 555 if ( GetTransaction(reffundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) != 0 )
556 {
557 fundingPubKey = tx.vout[1].scriptPubKey;
558 } else return(0);
4d2b7323 559 GetCCaddress(cp,coinaddr,dicepk);
10078e85 560 SetCCunspents(unspentOutputs,coinaddr);
04cf9f60 561 entropyval = 0;
10078e85 562 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
563 {
564 txid = it->first.txhash;
565 vout = (int32_t)it->first.index;
566 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
567 {
4d2b7323 568 //char str[65],str2[65];
54519f69 569 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
10078e85 570 {
571 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
572 {
4d2b7323 573 if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 10000 && (funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T') )
04cf9f60 574 {
4d2b7323 575 if ( funcid != 'F' && funcid != 'T' )
14debc6d 576 {
4d2b7323 577 n++;
14debc6d 578 fprintf(stderr,"(%c %.8f) ",funcid,(double)nValue/COIN);
579 }
10078e85 580 totalinputs += nValue;
14debc6d 581 if ( first == 0 && (funcid == 'E' || funcid == 'W' || funcid == 'L') )
04cf9f60 582 {
14debc6d 583 if ( fundingPubKey == tx.vout[1].scriptPubKey )
4d2b7323 584 {
14debc6d 585 if ( funcid == 'E' )
4d2b7323 586 {
f7af30ae 587 if ( GetTransaction(tx.vin[0].prevout.hash,vinTx,hashBlock,false) == 0 )
8eef6813 588 {
4b4113dd 589 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());
8eef6813 590 continue;
591 }
f7af30ae 592 if ( vinTx.vout[tx.vin[0].prevout.n].scriptPubKey != fundingPubKey )
14debc6d 593 {
385f6db0 594 uint8_t *ptr0,*ptr1; int32_t i;
f7af30ae 595 ptr0 = (uint8_t *)vinTx.vout[tx.vin[0].prevout.n].scriptPubKey.data();
385f6db0 596 ptr1 = (uint8_t *)fundingPubKey.data();
f7af30ae 597 for (i=0; i<tx.vout[tx.vin[0].prevout.n].scriptPubKey.size(); i++)
385f6db0 598 fprintf(stderr,"%02x",ptr0[i]);
599 fprintf(stderr," script vs ");
600 for (i=0; i<fundingPubKey.size(); i++)
601 fprintf(stderr,"%02x",ptr1[i]);
6138f598 602 fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch\n",funcid,tx.vin[0].prevout.n);
14debc6d 603 continue;
604 }
4d2b7323 605 }
14debc6d 606 entropytxid = txid;
607 entropyval = tx.vout[0].nValue;
608 first = 1;
04a4df80 609 }
04cf9f60 610 }
d4c504f0 611 } //else fprintf(stderr,"%c refsbits.%llx sbits.%llx nValue %.8f\n",funcid,(long long)refsbits,(long long)sbits,(double)nValue/COIN);
612 } //else fprintf(stderr,"else case funcid (%c) %d %s vs %s\n",funcid,funcid,uint256_str(str,reffundingtxid),uint256_str(str2,fundingtxid));
06811319 613 } //else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
10078e85 614 }
615 }
4d2b7323 616 fprintf(stderr,"numentropy tx %d: %.8f\n",n,(double)totalinputs/COIN);
10078e85 617 return(totalinputs);
618}
619
aec296a5 620bool 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 621{
622 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
623 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
624 GetCCaddress(cp,CCaddr,dicepk);
3c3451b8 625 SetCCtxids(txids,cp->normaladdr);
aec296a5 626 if ( fundingtxid != zeroid ) // avoid scan unless creating new funding plan
627 {
83da810c 628 if ( GetTransaction(fundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
aec296a5 629 {
630 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' && sbits == refsbits )
631 {
632 fundingPubKey = tx.vout[1].scriptPubKey;
633 return(true);
634 }
635 }
636 return(false);
637 }
10078e85 638 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
639 {
640 //int height = it->first.blockHeight;
641 txid = it->first.txhash;
a03bb7fa 642 if ( fundingtxid != zeroid && txid != fundingtxid )
643 continue;
10078e85 644 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
645 {
9025093e 646 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' )
10078e85 647 {
648 if ( sbits == refsbits )
a03bb7fa 649 {
aec296a5 650 fundingPubKey = tx.vout[1].scriptPubKey;
a03bb7fa 651 fundingtxid = txid;
10078e85 652 return(true);
a03bb7fa 653 }
10078e85 654 }
655 }
656 }
657 return(false);
658}
659
46a40047 660struct 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 661{
28500c30 662 struct CCcontract_info *cp; int32_t cmpflag;
a03bb7fa 663 cp = CCinit(C,EVAL_DICE);
664 if ( txfee == 0 )
665 txfee = 10000;
666 mypk = pubkey2pk(Mypubkey());
667 dicepk = GetUnspendable(cp,0);
668 sbits = stringbits(planstr);
669 if ( reffundingtxid == zeroid )
670 cmpflag = 0;
671 else cmpflag = 1;
28500c30 672 if ( DicePlanExists(fundingPubKey,reffundingtxid,cp,sbits,dicepk,minbet,maxbet,maxodds,timeoutblocks) != cmpflag )
a03bb7fa 673 {
97b0bc3a 674 fprintf(stderr,"Dice plan (%s) already exists cmpflag.%d\n",planstr,cmpflag);
a03bb7fa 675 return(0);
676 }
677 return(cp);
678}
679
10078e85 680UniValue DiceInfo(uint256 diceid)
681{
f516779c 682 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 683 if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 )
684 {
685 fprintf(stderr,"cant find fundingtxid\n");
686 result.push_back(Pair("error","cant find fundingtxid"));
687 return(result);
688 }
9025093e 689 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 0 )
10078e85 690 {
691 fprintf(stderr,"fundingtxid isnt dice creation txid\n");
692 result.push_back(Pair("error","fundingtxid isnt dice creation txid"));
693 return(result);
694 }
695 result.push_back(Pair("result","success"));
696 result.push_back(Pair("fundingtxid",uint256_str(str,diceid)));
697 unstringbits(str,sbits);
698 result.push_back(Pair("name",str));
699 result.push_back(Pair("sbits",sbits));
d0d96ab0 700 sprintf(numstr,"%.8f",(double)minbet/COIN);
701 result.push_back(Pair("minbet",numstr));
702 sprintf(numstr,"%.8f",(double)maxbet/COIN);
703 result.push_back(Pair("maxbet",numstr));
704 result.push_back(Pair("maxodds",maxodds));
9025093e 705 result.push_back(Pair("timeoutblocks",timeoutblocks));
f516779c 706 cp = CCinit(&C,EVAL_DICE);
707 dicepk = GetUnspendable(cp,0);
688d3ac4 708 funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,diceid);
f516779c 709 sprintf(numstr,"%.8f",(double)funding/COIN);
10078e85 710 result.push_back(Pair("funding",numstr));
711 return(result);
712}
713
714UniValue DiceList()
cfea7a46 715{
9025093e 716 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 717 cp = CCinit(&C,EVAL_DICE);
718 SetCCtxids(addressIndex,cp->normaladdr);
719 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
720 {
721 txid = it->first.txhash;
722 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
723 {
9025093e 724 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 0 )
10078e85 725 {
726 result.push_back(uint256_str(str,txid));
727 }
728 }
729 }
730 return(result);
731}
732
9025093e 733std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
05177cfb 734{
aec296a5 735 CMutableTransaction mtx; uint256 zero; CScript fundingPubKey; CPubKey mypk,dicepk; int64_t a,b,c,d; uint64_t sbits; struct CCcontract_info *cp,C;
9025093e 736 if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || timeoutblocks < 0 || timeoutblocks > 1440 )
05177cfb 737 {
738 fprintf(stderr,"negative parameter error\n");
739 return(0);
740 }
aec296a5 741 memset(&zero,0,sizeof(zero));
742 if ( (cp= Diceinit(fundingPubKey,zero,&C,planstr,txfee,mypk,dicepk,sbits,a,b,c,d)) == 0 )
05177cfb 743 return(0);
32e3be87 744 if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 )
10078e85 745 {
746 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk));
32e3be87 747 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
10078e85 748 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG));
9025093e 749 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,timeoutblocks)));
10078e85 750 }
751 fprintf(stderr,"cant find enough inputs\n");
752 return(0);
753}
754
755std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
756{
aec296a5 757 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 758 if ( amount < 0 )
759 {
760 fprintf(stderr,"negative parameter error\n");
761 return(0);
762 }
aec296a5 763 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
10078e85 764 return(0);
aec296a5 765 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
ef979a50 766 if ( 0 )
792cef06 767 {
768 uint8_t *ptr0,*ptr1; int32_t i;
769 ptr0 = (uint8_t *)scriptPubKey.data();
770 ptr1 = (uint8_t *)fundingPubKey.data();
771 for (i=0; i<35; i++)
772 fprintf(stderr,"%02x",ptr0[i]);
773 fprintf(stderr," script vs ");
774 for (i=0; i<35; i++)
775 fprintf(stderr,"%02x",ptr1[i]);
776 fprintf(stderr," funding\n");
777 }
aec296a5 778 if ( scriptPubKey == fundingPubKey )
10078e85 779 {
aec296a5 780 if ( AddNormalinputs(mtx,mypk,amount+2*txfee,64) > 0 )
781 {
782 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
783 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk));
7377f6ea 784 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
aec296a5 785 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('E',sbits,fundingtxid,hentropy,zeroid)));
786 } else fprintf(stderr,"cant find enough inputs\n");
787 } else fprintf(stderr,"only fund creator can add more funds (entropy)\n");
cfea7a46 788 return(0);
789}
790
7347a801 791std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds)
5d3d3a87 792{
aec296a5 793 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 794 if ( bet < 0 || odds < 1 )
5d3d3a87 795 {
796 fprintf(stderr,"negative parameter error\n");
797 return(0);
798 }
aec296a5 799 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
7347a801 800 return(0);
801 if ( bet < minbet || bet > maxbet || odds > maxodds )
802 {
803 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);
804 return(0);
805 }
7eb60411 806 if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid)) >= 2*bet*odds+txfee && entropyval != 0 )
7347a801 807 {
808 mtx.vin.push_back(CTxIn(entropytxid,0,CScript()));
809 if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 )
810 {
811 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
812 mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk));
813 mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk));
814 mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
afef48c0 815 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('B',sbits,fundingtxid,entropy,zeroid)));
7347a801 816 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN);
817 }
818 if ( entropyval == 0 && funding != 0 )
819 fprintf(stderr,"cant find dice entropy inputs\n");
820 else fprintf(stderr,"cant find dice inputs\n");
821 return(0);
822}
823
cfdc3770 824std::string DiceWinLoseTimeout(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout)
7347a801 825{
4d2b7323 826 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 827 *resultp = 0;
aec296a5 828 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
113adfd4 829 return("0");
aec296a5 830 if ( winlosetimeout != 0 )
831 {
832 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
833 if ( scriptPubKey != fundingPubKey )
834 {
835 fprintf(stderr,"only dice fund creator can submit winner or loser\n");
113adfd4 836 return("0");
aec296a5 837 }
838 }
a03bb7fa 839 if ( GetTransaction(bettxid,betTx,hashBlock,false) != 0 && GetTransaction(betTx.vin[0].prevout.hash,entropyTx,hashBlock,false) != 0 )
5d3d3a87 840 {
a03bb7fa 841 bettorentropy = DiceGetEntropy(betTx,'B');
4d2b7323 842 if ( winlosetimeout == 0 || (iswin= DiceIsWinner(hentropyproof,bettxid,betTx,entropyTx,bettorentropy,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
a03bb7fa 843 {
02409974 844 if ( iswin == winlosetimeout )
a03bb7fa 845 {
ef979a50 846 //fprintf(stderr,"iswin.%d matches\n",iswin);
7eb60411 847 mtx.vin.push_back(CTxIn(bettxid,0,CScript()));
848 mtx.vin.push_back(CTxIn(bettxid,1,CScript()));
a03bb7fa 849 if ( iswin == 0 )
7eb60411 850 {
02409974 851 funcid = 'T';
4d2b7323 852 if ( DiceVerifyTimeout(betTx,timeoutblocks) == 0 ) // hasnt timed out yet
853 {
854 fprintf(stderr,"timeout is not supported yet\n");
855 return(0);
856 }
857 else
858 {
859 hentropy = hentropyproof = zeroid;
860 iswin = 1;
861 }
7eb60411 862 }
4d2b7323 863 if ( iswin > 0 )
7eb60411 864 {
a03bb7fa 865 funcid = 'W';
7eb60411 866 odds = (betTx.vout[2].nValue - txfee);
867 if ( odds < 1 || odds > maxodds )
868 {
869 fprintf(stderr,"illegal odds.%d vs maxodds.%d\n",(int32_t)odds,(int32_t)maxodds);
113adfd4 870 return("0");
7eb60411 871 }
872 CCchange = betTx.vout[0].nValue;
873 fundsneeded = 2*txfee + (odds-1)*betTx.vout[1].nValue;
4d2b7323 874 if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60)) > 0 )
7eb60411 875 {
3454564b 876 if ( inputs > fundsneeded )
877 CCchange += (inputs - fundsneeded);
7eb60411 878 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk));
04a4df80 879 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
7eb60411 880 mtx.vout.push_back(CTxOut(odds * betTx.vout[1].nValue,betTx.vout[2].scriptPubKey));
881 }
882 else
883 {
884 fprintf(stderr,"not enough inputs for %.8f\n",(double)fundsneeded/COIN);
113adfd4 885 return("0");
7eb60411 886 }
887 }
888 else
a03bb7fa 889 {
7eb60411 890 funcid = 'L';
891 mtx.vout.push_back(MakeCC1vout(cp->evalcode,betTx.vout[0].nValue + betTx.vout[1].nValue - txfee,dicepk));
04a4df80 892 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
7eb60411 893 }
4d2b7323 894 if ( winlosetimeout != 0 )
895 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
cfdc3770 896 *resultp = 1;
ef979a50 897 //char str[65],str2[65];
898 //fprintf(stderr,"iswin.%d house entropy %s vs bettor %s\n",iswin,uint256_str(str,hentropyproof),uint256_str(str2,bettorentropy));
afef48c0 899 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet(funcid,sbits,fundingtxid,hentropy,hentropyproof)));
e0ea3b3e 900 } else fprintf(stderr,"iswin.%d does not match.%d\n",iswin,winlosetimeout);
113adfd4 901 } else return("0");
a03bb7fa 902 }
113adfd4 903 return("0");
5d3d3a87 904}
905
This page took 0.185107 seconds and 4 git commands to generate.