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