]> 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 {
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");
502dad46 433 else if ( eval->GetTxUnconfirmed(vinTx.vin[0].prevout.hash,vinofvinTx,hashBlock) == 0 || vinofvinTx.vout.size() < 1 )
4d2b7323 434 return eval->Invalid("always should find vinofvin.0, but didnt for bet");
502dad46 435 else if ( vinofvinTx.vout[0].scriptPubKey != fundingPubKey )
8a2146db 436 {
7a241adb 437 uint8_t *ptr0,*ptr1; int32_t i; char str[65];
502dad46 438 fprintf(stderr,"bidTx.%s\n",uint256_str(str,txid));
439 fprintf(stderr,"entropyTx.%s v%d\n",uint256_str(str,tx.vin[0].prevout.hash),(int32_t)tx.vin[0].prevout.n);
440 fprintf(stderr,"entropyTx vin0 %s v%d\n",uint256_str(str,vinTx.vin[0].prevout.hash),(int32_t)vinTx.vin[0].prevout.n);
441 ptr0 = (uint8_t *)vinofvinTx.vout[0].scriptPubKey.data();
8a2146db 442 ptr1 = (uint8_t *)fundingPubKey.data();
502dad46 443 for (i=0; i<vinofvinTx.vout[0].scriptPubKey.size(); i++)
8a2146db 444 fprintf(stderr,"%02x",ptr0[i]);
445 fprintf(stderr," script vs ");
446 for (i=0; i<fundingPubKey.size(); i++)
447 fprintf(stderr,"%02x",ptr1[i]);
7a241adb 448 fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch %s\n",funcid,vinTx.vin[0].prevout.n,uint256_str(str,vinTx.vin[0].prevout.hash));
7f63070b 449 return eval->Invalid("vin1 of entropy tx not fundingPubKey for bet");
8a2146db 450 }
4d2b7323 451 else if ( vinTx.vout[vinTx.vin[0].prevout.n].nValue != tx.vout[0].nValue )
452 return eval->Invalid("vout.0 nValue != entropy nValue for bet");
aec296a5 453 if ( (iswin= DiceIsWinner(entropy,txid,tx,vinTx,hash,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
1c87477b 454 {
4d2b7323 455 // will only happen for fundingPubKey
fb89b441 456 DiceQueue(iswin,sbits,fundingtxid,txid);
1c87477b 457 }
10078e85 458 break;
5d3d3a87 459 case 'L':
5d3d3a87 460 case 'W':
02409974 461 case 'T':
7eb60411 462 //vin.0: betTx CC vout.0 entropy from bet
463 //vin.1: betTx CC vout.1 bet amount from bet
02409974 464 //vin.2+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T'
7eb60411 465 //vout.1: tag to owner address for entropy funds
4d2b7323 466 preventCCvouts = 1;
467 DiceAmounts(inputs,outputs,cp,eval,tx);
468 if ( IsCCInput(tx.vin[0].scriptSig) == 0 || IsCCInput(tx.vin[1].scriptSig) == 0 )
469 return eval->Invalid("vin0 or vin1 normal vin for bet");
470 else if ( tx.vin[0].prevout.hash != tx.vin[1].prevout.hash )
471 return eval->Invalid("vin0 != vin1 prevout.hash for bet");
472 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
473 return eval->Invalid("always should find vin.0, but didnt for wlt");
474 else if ( vinTx.vout.size() < 3 || DecodeDiceOpRet(tx.vin[0].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,vinhentropy,vinproof) != 'B' )
475 return eval->Invalid("not betTx for vin0/1 for wlt");
476 else if ( sbits != vinsbits || fundingtxid != vinfundingtxid )
477 return eval->Invalid("sbits or fundingtxid mismatch for wlt");
478 else if ( fundingPubKey != tx.vout[1].scriptPubKey )
479 return eval->Invalid("tx.vout[1] != fundingPubKey for wlt");
480 if ( funcid == 'L' )
10078e85 481 {
4d2b7323 482 //vout.0: funding CC to entropy owner
483 //vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof
484 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,inputs-txfee) == 0 )
485 return eval->Invalid("vout[0] != inputs-txfee for loss");
486 iswin = -1;
10078e85 487 }
4d2b7323 488 else
489 {
490 //vout.0: funding CC change to entropy owner
491 //vout.2: normal output to bettor's address
492 //vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof
493 odds = vinTx.vout[2].nValue - txfee;
494 if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 )
495 return eval->Invalid("vout[0] != inputs-txfee for win/timeout");
496 else if ( tx.vout[2].scriptPubKey != vinTx.vout[2].scriptPubKey )
497 return eval->Invalid("vout[2] scriptPubKey mismatch for win/timeout");
498 else if ( tx.vout[2].nValue != odds*vinTx.vout[1].nValue )
499 return eval->Invalid("vout[2] payut mismatch for win/timeout");
3454564b 500 else if ( inputs != (outputs + tx.vout[2].nValue + 2*txfee) )
d2c1a2f2 501 {
502 fprintf(stderr,"inputs %.8f != outputs %.8f + 2 %.8f - txfee\n",(double)inputs/COIN,(double)outputs/COIN,(double)tx.vout[2].nValue/COIN);
4d2b7323 503 return eval->Invalid("CC funds mismatch for win/timeout");
d2c1a2f2 504 }
4d2b7323 505 iswin = (funcid == 'W');
506 }
507 if ( iswin != 0 )
508 {
ef979a50 509 //char str[65],str2[65];
53f6ead6 510 entropy = DiceGetEntropy(vinTx,'B');
e7479ef8 511 vcalc_sha256(0,(uint8_t *)&hash,(uint8_t *)&proof,32);
ef979a50 512 //fprintf(stderr,"calculated house hentropy.%s\n",uint256_str(str,hash));
513 //fprintf(stderr,"verify house entropy %s vs bettor %s\n",uint256_str(str,proof),uint256_str(str2,entropy));
53f6ead6 514 winnings = DiceCalc(vinTx.vout[1].nValue,vinTx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,proof,entropy);
4d2b7323 515 if ( (winnings == 0 && iswin > 0) || (winnings > 0 && iswin < 0) )
516 return eval->Invalid("DiceCalc mismatch for win/loss");
517 }
518 else if ( DiceVerifyTimeout(vinTx,timeoutblocks) == 0 )
519 return eval->Invalid("invalid timeout claim for timeout");
10078e85 520 break;
cfea7a46 521 }
522 }
10078e85 523 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
cfea7a46 524 }
10078e85 525 return(true);
cfea7a46 526}
cfea7a46 527
4d2b7323 528uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
cfea7a46 529{
54519f69 530 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 531 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
532 GetCCaddress(cp,coinaddr,pk);
533 SetCCunspents(unspentOutputs,coinaddr);
534 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
535 {
536 txid = it->first.txhash;
10078e85 537 vout = (int32_t)it->first.index;
93ac96fa 538 if ( it->second.satoshis < 1000000 )
c2342f7b 539 continue;
ef979a50 540 //fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
10078e85 541 for (j=0; j<mtx.vin.size(); j++)
542 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
543 break;
544 if ( j != mtx.vin.size() )
545 continue;
546 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
cfea7a46 547 {
54519f69 548 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
cfea7a46 549 {
4d2b7323 550 if ( funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T' )
10078e85 551 {
4d2b7323 552 if ( total != 0 && maxinputs != 0 )
553 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
554 totalinputs += it->second.satoshis;
555 n++;
556 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
557 break;
10078e85 558 }
10078e85 559 } else fprintf(stderr,"null funcid\n");
cfea7a46 560 }
561 }
562 return(totalinputs);
563}
564
4d2b7323 565uint64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey dicepk,uint256 reffundingtxid)
10078e85 566{
e9c75366 567 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 568 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
a1b43551 569 if ( GetTransaction(reffundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) != 0 )
570 {
571 fundingPubKey = tx.vout[1].scriptPubKey;
572 } else return(0);
4d2b7323 573 GetCCaddress(cp,coinaddr,dicepk);
10078e85 574 SetCCunspents(unspentOutputs,coinaddr);
04cf9f60 575 entropyval = 0;
10078e85 576 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
577 {
578 txid = it->first.txhash;
579 vout = (int32_t)it->first.index;
580 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
581 {
4d2b7323 582 //char str[65],str2[65];
54519f69 583 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
10078e85 584 {
585 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
586 {
4d2b7323 587 if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 10000 && (funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T') )
04cf9f60 588 {
4d2b7323 589 if ( funcid != 'F' && funcid != 'T' )
14debc6d 590 {
4d2b7323 591 n++;
14debc6d 592 fprintf(stderr,"(%c %.8f) ",funcid,(double)nValue/COIN);
593 }
10078e85 594 totalinputs += nValue;
14debc6d 595 if ( first == 0 && (funcid == 'E' || funcid == 'W' || funcid == 'L') )
04cf9f60 596 {
14debc6d 597 if ( fundingPubKey == tx.vout[1].scriptPubKey )
4d2b7323 598 {
14debc6d 599 if ( funcid == 'E' )
4d2b7323 600 {
f7af30ae 601 if ( GetTransaction(tx.vin[0].prevout.hash,vinTx,hashBlock,false) == 0 )
8eef6813 602 {
4b4113dd 603 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 604 continue;
605 }
502dad46 606 if ( vinTx.vout[0].scriptPubKey != fundingPubKey )
14debc6d 607 {
385f6db0 608 uint8_t *ptr0,*ptr1; int32_t i;
502dad46 609 ptr0 = (uint8_t *)vinTx.vout[0].scriptPubKey.data();
385f6db0 610 ptr1 = (uint8_t *)fundingPubKey.data();
502dad46 611 for (i=0; i<vinTx.vout[0].scriptPubKey.size(); i++)
385f6db0 612 fprintf(stderr,"%02x",ptr0[i]);
613 fprintf(stderr," script vs ");
614 for (i=0; i<fundingPubKey.size(); i++)
615 fprintf(stderr,"%02x",ptr1[i]);
6138f598 616 fprintf(stderr," (%c) entropy vin.%d fundingPubKey mismatch\n",funcid,tx.vin[0].prevout.n);
14debc6d 617 continue;
618 }
4d2b7323 619 }
14debc6d 620 entropytxid = txid;
621 entropyval = tx.vout[0].nValue;
622 first = 1;
04a4df80 623 }
04cf9f60 624 }
d4c504f0 625 } //else fprintf(stderr,"%c refsbits.%llx sbits.%llx nValue %.8f\n",funcid,(long long)refsbits,(long long)sbits,(double)nValue/COIN);
626 } //else fprintf(stderr,"else case funcid (%c) %d %s vs %s\n",funcid,funcid,uint256_str(str,reffundingtxid),uint256_str(str2,fundingtxid));
06811319 627 } //else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
10078e85 628 }
629 }
4d2b7323 630 fprintf(stderr,"numentropy tx %d: %.8f\n",n,(double)totalinputs/COIN);
10078e85 631 return(totalinputs);
632}
633
aec296a5 634bool 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 635{
636 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
637 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
638 GetCCaddress(cp,CCaddr,dicepk);
3c3451b8 639 SetCCtxids(txids,cp->normaladdr);
aec296a5 640 if ( fundingtxid != zeroid ) // avoid scan unless creating new funding plan
641 {
83da810c 642 if ( GetTransaction(fundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
aec296a5 643 {
644 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' && sbits == refsbits )
645 {
646 fundingPubKey = tx.vout[1].scriptPubKey;
647 return(true);
648 }
649 }
650 return(false);
651 }
10078e85 652 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
653 {
654 //int height = it->first.blockHeight;
655 txid = it->first.txhash;
a03bb7fa 656 if ( fundingtxid != zeroid && txid != fundingtxid )
657 continue;
10078e85 658 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
659 {
9025093e 660 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' )
10078e85 661 {
662 if ( sbits == refsbits )
a03bb7fa 663 {
aec296a5 664 fundingPubKey = tx.vout[1].scriptPubKey;
a03bb7fa 665 fundingtxid = txid;
10078e85 666 return(true);
a03bb7fa 667 }
10078e85 668 }
669 }
670 }
671 return(false);
672}
673
46a40047 674struct 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 675{
28500c30 676 struct CCcontract_info *cp; int32_t cmpflag;
a03bb7fa 677 cp = CCinit(C,EVAL_DICE);
678 if ( txfee == 0 )
679 txfee = 10000;
680 mypk = pubkey2pk(Mypubkey());
681 dicepk = GetUnspendable(cp,0);
682 sbits = stringbits(planstr);
683 if ( reffundingtxid == zeroid )
684 cmpflag = 0;
685 else cmpflag = 1;
28500c30 686 if ( DicePlanExists(fundingPubKey,reffundingtxid,cp,sbits,dicepk,minbet,maxbet,maxodds,timeoutblocks) != cmpflag )
a03bb7fa 687 {
97b0bc3a 688 fprintf(stderr,"Dice plan (%s) already exists cmpflag.%d\n",planstr,cmpflag);
a03bb7fa 689 return(0);
690 }
691 return(cp);
692}
693
10078e85 694UniValue DiceInfo(uint256 diceid)
695{
f516779c 696 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 697 if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 )
698 {
699 fprintf(stderr,"cant find fundingtxid\n");
700 result.push_back(Pair("error","cant find fundingtxid"));
701 return(result);
702 }
9025093e 703 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 0 )
10078e85 704 {
705 fprintf(stderr,"fundingtxid isnt dice creation txid\n");
706 result.push_back(Pair("error","fundingtxid isnt dice creation txid"));
707 return(result);
708 }
709 result.push_back(Pair("result","success"));
710 result.push_back(Pair("fundingtxid",uint256_str(str,diceid)));
711 unstringbits(str,sbits);
712 result.push_back(Pair("name",str));
713 result.push_back(Pair("sbits",sbits));
d0d96ab0 714 sprintf(numstr,"%.8f",(double)minbet/COIN);
715 result.push_back(Pair("minbet",numstr));
716 sprintf(numstr,"%.8f",(double)maxbet/COIN);
717 result.push_back(Pair("maxbet",numstr));
718 result.push_back(Pair("maxodds",maxodds));
9025093e 719 result.push_back(Pair("timeoutblocks",timeoutblocks));
f516779c 720 cp = CCinit(&C,EVAL_DICE);
721 dicepk = GetUnspendable(cp,0);
688d3ac4 722 funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,diceid);
f516779c 723 sprintf(numstr,"%.8f",(double)funding/COIN);
10078e85 724 result.push_back(Pair("funding",numstr));
725 return(result);
726}
727
728UniValue DiceList()
cfea7a46 729{
9025093e 730 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 731 cp = CCinit(&C,EVAL_DICE);
732 SetCCtxids(addressIndex,cp->normaladdr);
733 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
734 {
735 txid = it->first.txhash;
736 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
737 {
9025093e 738 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 0 )
10078e85 739 {
740 result.push_back(uint256_str(str,txid));
741 }
742 }
743 }
744 return(result);
745}
746
9025093e 747std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks)
05177cfb 748{
aec296a5 749 CMutableTransaction mtx; uint256 zero; CScript fundingPubKey; CPubKey mypk,dicepk; int64_t a,b,c,d; uint64_t sbits; struct CCcontract_info *cp,C;
9025093e 750 if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || timeoutblocks < 0 || timeoutblocks > 1440 )
05177cfb 751 {
752 fprintf(stderr,"negative parameter error\n");
753 return(0);
754 }
aec296a5 755 memset(&zero,0,sizeof(zero));
756 if ( (cp= Diceinit(fundingPubKey,zero,&C,planstr,txfee,mypk,dicepk,sbits,a,b,c,d)) == 0 )
05177cfb 757 return(0);
32e3be87 758 if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 )
10078e85 759 {
760 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk));
32e3be87 761 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
10078e85 762 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG));
9025093e 763 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,timeoutblocks)));
10078e85 764 }
765 fprintf(stderr,"cant find enough inputs\n");
766 return(0);
767}
768
769std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
770{
aec296a5 771 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 772 if ( amount < 0 )
773 {
774 fprintf(stderr,"negative parameter error\n");
775 return(0);
776 }
aec296a5 777 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
10078e85 778 return(0);
aec296a5 779 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
ef979a50 780 if ( 0 )
792cef06 781 {
782 uint8_t *ptr0,*ptr1; int32_t i;
783 ptr0 = (uint8_t *)scriptPubKey.data();
784 ptr1 = (uint8_t *)fundingPubKey.data();
785 for (i=0; i<35; i++)
786 fprintf(stderr,"%02x",ptr0[i]);
787 fprintf(stderr," script vs ");
788 for (i=0; i<35; i++)
789 fprintf(stderr,"%02x",ptr1[i]);
790 fprintf(stderr," funding\n");
791 }
aec296a5 792 if ( scriptPubKey == fundingPubKey )
10078e85 793 {
aec296a5 794 if ( AddNormalinputs(mtx,mypk,amount+2*txfee,64) > 0 )
795 {
796 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
797 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk));
7377f6ea 798 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
aec296a5 799 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('E',sbits,fundingtxid,hentropy,zeroid)));
800 } else fprintf(stderr,"cant find enough inputs\n");
801 } else fprintf(stderr,"only fund creator can add more funds (entropy)\n");
cfea7a46 802 return(0);
803}
804
7347a801 805std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds)
5d3d3a87 806{
aec296a5 807 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 808 if ( bet < 0 || odds < 1 )
5d3d3a87 809 {
810 fprintf(stderr,"negative parameter error\n");
811 return(0);
812 }
aec296a5 813 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
7347a801 814 return(0);
815 if ( bet < minbet || bet > maxbet || odds > maxodds )
816 {
817 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);
818 return(0);
819 }
7eb60411 820 if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid)) >= 2*bet*odds+txfee && entropyval != 0 )
7347a801 821 {
822 mtx.vin.push_back(CTxIn(entropytxid,0,CScript()));
823 if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 )
824 {
825 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
826 mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk));
827 mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk));
828 mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
afef48c0 829 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('B',sbits,fundingtxid,entropy,zeroid)));
7347a801 830 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN);
831 }
832 if ( entropyval == 0 && funding != 0 )
833 fprintf(stderr,"cant find dice entropy inputs\n");
834 else fprintf(stderr,"cant find dice inputs\n");
835 return(0);
836}
837
cfdc3770 838std::string DiceWinLoseTimeout(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout)
7347a801 839{
4d2b7323 840 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 841 *resultp = 0;
aec296a5 842 if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 )
113adfd4 843 return("0");
aec296a5 844 if ( winlosetimeout != 0 )
845 {
846 scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG;
847 if ( scriptPubKey != fundingPubKey )
848 {
849 fprintf(stderr,"only dice fund creator can submit winner or loser\n");
113adfd4 850 return("0");
aec296a5 851 }
852 }
a03bb7fa 853 if ( GetTransaction(bettxid,betTx,hashBlock,false) != 0 && GetTransaction(betTx.vin[0].prevout.hash,entropyTx,hashBlock,false) != 0 )
5d3d3a87 854 {
a03bb7fa 855 bettorentropy = DiceGetEntropy(betTx,'B');
4d2b7323 856 if ( winlosetimeout == 0 || (iswin= DiceIsWinner(hentropyproof,bettxid,betTx,entropyTx,bettorentropy,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 )
a03bb7fa 857 {
02409974 858 if ( iswin == winlosetimeout )
a03bb7fa 859 {
ef979a50 860 //fprintf(stderr,"iswin.%d matches\n",iswin);
7eb60411 861 mtx.vin.push_back(CTxIn(bettxid,0,CScript()));
862 mtx.vin.push_back(CTxIn(bettxid,1,CScript()));
a03bb7fa 863 if ( iswin == 0 )
7eb60411 864 {
02409974 865 funcid = 'T';
4d2b7323 866 if ( DiceVerifyTimeout(betTx,timeoutblocks) == 0 ) // hasnt timed out yet
867 {
868 fprintf(stderr,"timeout is not supported yet\n");
869 return(0);
870 }
871 else
872 {
873 hentropy = hentropyproof = zeroid;
874 iswin = 1;
875 }
7eb60411 876 }
4d2b7323 877 if ( iswin > 0 )
7eb60411 878 {
a03bb7fa 879 funcid = 'W';
7eb60411 880 odds = (betTx.vout[2].nValue - txfee);
881 if ( odds < 1 || odds > maxodds )
882 {
883 fprintf(stderr,"illegal odds.%d vs maxodds.%d\n",(int32_t)odds,(int32_t)maxodds);
113adfd4 884 return("0");
7eb60411 885 }
886 CCchange = betTx.vout[0].nValue;
887 fundsneeded = 2*txfee + (odds-1)*betTx.vout[1].nValue;
4d2b7323 888 if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60)) > 0 )
7eb60411 889 {
3454564b 890 if ( inputs > fundsneeded )
891 CCchange += (inputs - fundsneeded);
7eb60411 892 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk));
04a4df80 893 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
7eb60411 894 mtx.vout.push_back(CTxOut(odds * betTx.vout[1].nValue,betTx.vout[2].scriptPubKey));
895 }
896 else
897 {
898 fprintf(stderr,"not enough inputs for %.8f\n",(double)fundsneeded/COIN);
113adfd4 899 return("0");
7eb60411 900 }
901 }
902 else
a03bb7fa 903 {
7eb60411 904 funcid = 'L';
905 mtx.vout.push_back(MakeCC1vout(cp->evalcode,betTx.vout[0].nValue + betTx.vout[1].nValue - txfee,dicepk));
04a4df80 906 mtx.vout.push_back(CTxOut(txfee,fundingPubKey));
7eb60411 907 }
4d2b7323 908 if ( winlosetimeout != 0 )
909 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
cfdc3770 910 *resultp = 1;
ef979a50 911 //char str[65],str2[65];
912 //fprintf(stderr,"iswin.%d house entropy %s vs bettor %s\n",iswin,uint256_str(str,hentropyproof),uint256_str(str2,bettorentropy));
afef48c0 913 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet(funcid,sbits,fundingtxid,hentropy,hentropyproof)));
e0ea3b3e 914 } else fprintf(stderr,"iswin.%d does not match.%d\n",iswin,winlosetimeout);
113adfd4 915 } else return("0");
a03bb7fa 916 }
113adfd4 917 return("0");
5d3d3a87 918}
919
This page took 0.228981 seconds and 4 git commands to generate.