]> Git Repo - VerusCoin.git/blame - src/cc/dice.cpp
Adjust bettor /= odds
[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
18/*
10078e85 19 in order to implement a dice game, we need a source of entropy, reasonably fast completion time and a way to manage the utxos.
20
21 1. CC vout locks "house" funds with hash(entropy) + half of shared secret
22 2. bettor submits bet, with entropy, odds, houseid and sends combined amount into another CC vout.
23 3. house account sends funds to winner with proof of entropy
24 4. if timeout, bettor wins funds
25
26 2. and 3. can be done in mempool
27 */
cfea7a46 28
ae748eaf 29#include "../endian.h"
30
31void endiancpy(uint8_t *dest,uint8_t *src,int32_t len)
32{
33 int32_t i,j=0;
34#if defined(WORDS_BIGENDIAN)
35 for (i=31; i>=0; i--)
36 dest[j++] = src[i];
37#else
17bc6201 38 memcpy(dest,src,len);
ae748eaf 39#endif
40}
41
dfe4c146 42uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv) // max 1 vout per txid used
8138fad2 43{
ae748eaf 44 int32_t i; uint8_t _entropy[32],_hentropy[32]; bits256 tmp256,txidpub,txidpriv,mypriv,mypub,ssecret,ssecret2; uint256 hentropy;
72362bbe 45 memset(&hentropy,0,32);
e0e655fe 46 endiancpy(txidpriv.bytes,(uint8_t *)&_txidpriv,32);
d176d2df 47 txidpriv.bytes[0] &= 0xf8, txidpriv.bytes[31] &= 0x7f, txidpriv.bytes[31] |= 0x40;
48 txidpub = curve25519(txidpriv,curve25519_basepoint9());
49
50 Myprivkey(tmp256.bytes);
51 vcalc_sha256(0,mypriv.bytes,tmp256.bytes,32);
52 mypriv.bytes[0] &= 0xf8, mypriv.bytes[31] &= 0x7f, mypriv.bytes[31] |= 0x40;
53 mypub = curve25519(mypriv,curve25519_basepoint9());
54
91f21771 55 ssecret = curve25519(mypriv,txidpub);
56 ssecret2 = curve25519(txidpriv,mypub);
d176d2df 57 if ( memcmp(ssecret.bytes,ssecret2.bytes,32) == 0 )
8138fad2 58 {
ae748eaf 59 vcalc_sha256(0,(uint8_t *)&_entropy,ssecret.bytes,32);
60 vcalc_sha256(0,(uint8_t *)&_hentropy,_entropy,32);
dfe4c146 61 endiancpy((uint8_t *)&entropy,_entropy,32);
62 endiancpy((uint8_t *)&hentropy,_hentropy,32);
840a96ca 63 }
64 else
65 {
66 for (i=0; i<32; i++)
774b8b44 67 fprintf(stderr,"%02x",ssecret.bytes[i]);
840a96ca 68 fprintf(stderr," ssecret\n");
69 for (i=0; i<32; i++)
ac9816bb 70 fprintf(stderr,"%02x",ssecret2.bytes[i]);
840a96ca 71 fprintf(stderr," ssecret2 dont match\n");
72 }
8138fad2 73 return(hentropy);
74}
75
be7a410a 76uint64_t DiceCalc(int64_t bet,int64_t odds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks,uint256 houseentropy,uint256 bettorentropy)
10078e85 77{
b52f7685 78 uint8_t buf[64],_house[32],_bettor[32]; uint64_t winnings; arith_uint256 house,bettor; char str[65],str2[65];
98c6e2e1 79 if ( odds < 10000 )
10078e85 80 return(0);
98c6e2e1 81 else odds -= 10000;
be7a410a 82 if ( bet < minbet || bet > maxbet || odds > maxodds )
83 {
84 fprintf(stderr,"bet size violation %.8f\n",(double)bet/COIN);
85 return(0);
86 }
87 endiancpy(buf,(uint8_t *)&houseentropy,32);
88 endiancpy(&buf[32],(uint8_t *)&bettorentropy,32);
89 vcalc_sha256(0,(uint8_t *)&_house,buf,64);
208f0e7a 90 endiancpy((uint8_t *)&house,_house,32);
be7a410a 91
92 endiancpy(buf,(uint8_t *)&bettorentropy,32);
93 endiancpy(&buf[32],(uint8_t *)&houseentropy,32);
94 vcalc_sha256(0,(uint8_t *)&_house,buf,64);
208f0e7a 95 endiancpy((uint8_t *)&bettor,_bettor,32);
b52f7685 96 if ( odds > 1 )
97 bettor = (bettor / arith_uint256(odds));
98 if ( bettor >= house )
99 winnings = bet * odds;
100 else winnings = 0;
8a2eeb6b 101 fprintf(stderr,"bet %.8f at odds %d:1 %s vs %s\n",(double)bet/COIN,(int32_t)odds,uint256_str(str,*(uint256 *)&house),uint256_str(str2,*(uint256 *)&bettor));
d0d96ab0 102 return(0);
10078e85 103}
104
d0d96ab0 105CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
10078e85 106{
107 CScript opret; uint8_t evalcode = EVAL_DICE;
d0d96ab0 108 opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << forfeitblocks);
10078e85 109 return(opret);
110}
111
d0d96ab0 112uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &forfeitblocks)
10078e85 113{
114 std::vector<uint8_t> vopret; uint8_t *script,e,f;
115 GetOpReturnData(scriptPubKey, vopret);
116 script = (uint8_t *)vopret.data();
d0d96ab0 117 if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 0 )
10078e85 118 {
119 if ( e == EVAL_DICE && f == 'F' )
120 return(f);
121 }
122 return(0);
123}
124
8138fad2 125CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid,uint256 hash)
10078e85 126{
127 CScript opret; uint8_t evalcode = EVAL_DICE;
8138fad2 128 opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid << hash);
10078e85 129 return(opret);
130}
131
8138fad2 132uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid,uint256 &hash)
10078e85 133{
d0d96ab0 134 std::vector<uint8_t> vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,forfeitblocks;
10078e85 135 GetOpReturnData(scriptPubKey, vopret);
136 if ( vopret.size() > 2 )
137 {
138 script = (uint8_t *)vopret.data();
139 if ( script[0] == EVAL_DICE )
140 {
141 if ( script[1] == 'F' )
142 {
d0d96ab0 143 if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 0 )
10078e85 144 {
72362bbe 145 memset(&hash,0,32);
10078e85 146 fundingtxid = txid;
147 return('F');
148 } else fprintf(stderr,"unmarshal error for F\n");
149 }
8138fad2 150 else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid; ss >> hash) != 0 )
10078e85 151 {
28b947b8 152 if ( e == EVAL_DICE && (f == 'B' || f == 'U' || f == 'E') )
10078e85 153 return(f);
154 else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f);
155 }
156 } else fprintf(stderr,"script[0] %02x != EVAL_DICE\n",script[0]);
157 } else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
158 return(0);
159}
cfea7a46 160
161uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
162{
163 char destaddr[64];
164 if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
165 {
166 if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
167 return(tx.vout[v].nValue);
168 }
169 return(0);
170}
171
10078e85 172bool DiceExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee)
cfea7a46 173{
174 static uint256 zerohash;
10078e85 175 CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis;
cfea7a46 176 numvins = tx.vin.size();
177 numvouts = tx.vout.size();
178 for (i=0; i<numvins; i++)
179 {
cfea7a46 180 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
181 {
cfea7a46 182 if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
10078e85 183 return eval->Invalid("always should find vin, but didnt");
cfea7a46 184 else
185 {
cfea7a46 186 if ( hashBlock == zerohash )
187 return eval->Invalid("cant dice from mempool");
188 if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
189 inputs += assetoshis;
190 }
191 }
192 }
193 for (i=0; i<numvouts; i++)
194 {
195 //fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
196 if ( (assetoshis= IsDicevout(cp,tx,i)) != 0 )
197 outputs += assetoshis;
198 }
10078e85 199 if ( inputs != outputs+txfee )
cfea7a46 200 {
201 fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
10078e85 202 return eval->Invalid("mismatched inputs != outputs + txfee");
cfea7a46 203 }
204 else return(true);
205}
206
1c87477b 207bool DiceIsmine(const CScript scriptPubKey)
208{
209 char destaddr[64],myaddr[64];
210 Getscriptaddress(destaddr,scriptPubKey);
ca05cbaa 211 Getscriptaddress(myaddr,CScript() << Mypubkey() << OP_CHECKSIG);
1c87477b 212 return(strcmp(destaddr,myaddr) == 0);
213}
214
cfea7a46 215bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
216{
72362bbe 217 uint256 txid,fundingtxid,hashBlock,hash; int64_t minbet,maxbet,maxodds,forfeitblocks; uint64_t sbits,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx;
cfea7a46 218 numvins = tx.vin.size();
219 numvouts = tx.vout.size();
220 preventCCvins = preventCCvouts = -1;
221 if ( numvouts < 1 )
222 return eval->Invalid("no vouts");
223 else
224 {
10078e85 225 txid = tx.GetHash();
72362bbe 226 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash)) != 0 )
cfea7a46 227 {
10078e85 228 if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
229 return eval->Invalid("cant find fundingtxid");
d0d96ab0 230 else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 'F' )
10078e85 231 return eval->Invalid("fundingTx not valid");
232 switch ( funcid )
cfea7a46 233 {
10078e85 234 case 'F':
235 //vins.*: normal inputs
236 //vout.0: CC vout for funding
237 //vout.1: normal marker vout for easy searching
238 //vout.2: normal change
239 //vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit
240 return eval->Invalid("unexpected DiceValidate for createfunding");
241 break;
28b947b8 242 case 'E':
10078e85 243 //vins.*: normal inputs
0d4cfd0b 244 //vout.0: CC vout for locked entropy funds
245 //vout.1: tag to owner address for entropy funds
246 //vout.2: normal change
28b947b8 247 //vout.n-1: opreturn 'E' sbits fundingtxid hentropy
248 return eval->Invalid("unexpected DiceValidate for addfunding entropy");
10078e85 249 break;
04cf9f60 250 case 'B':
28b947b8 251 //vin.0: entropy txid from house
252 //vins.1+: normal inputs
0d4cfd0b 253 //vout.0: CC vout for locked entropy
28b947b8 254 //vout.1: CC vout for locked bet
98c6e2e1 255 //vout.2: tag for bettor's address (txfee + odds)
28b947b8 256 //vout.3: change
257 //vout.n-1: opreturn 'B' sbits fundingtxid entropy
258 // get house hentropy and its vin0.prevtxid, cmp vout1 to owner address
259 // if owneraddress is me, then validate hentropy and submit outcome tx
260 fprintf(stderr,"got bet txid\n");
1c87477b 261 if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
262 return eval->Invalid("always should find vin.0, but didnt");
69d725fe 263 else if ( DiceIsmine(vinTx.vout[1].scriptPubKey) != 0 && vinTx.vout.size() > 0 )
1c87477b 264 {
77add0c1 265 uint64_t vinsbits,winnings; uint256 vinfundingtxid,hentropy,hentropy2,entropy; char str[65],str2[65];
da297d05 266 if ( DecodeDiceOpRet(txid,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,hentropy) == 'E' && sbits == vinsbits && fundingtxid == vinfundingtxid )
69d725fe 267 {
93235ec9 268 hentropy2 = DiceHashEntropy(entropy,vinTx.vin[0].prevout.hash);
a806f2fc 269 if ( hentropy == hentropy2 )
270 {
98c6e2e1 271 winnings = DiceCalc(tx.vout[1].nValue,tx.vout[2].nValue,minbet,maxbet,maxodds,forfeitblocks,entropy,hash);
be7a410a 272 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);
a806f2fc 273 }
69d725fe 274 }
1c87477b 275 }
28b947b8 276 return eval->Invalid("dont confirm bet during debug");
10078e85 277 break;
278 case 'U':
279 //vin.0: locked funds CC vout.0 from lock
28b947b8 280 //vin.1+: funding CC vout.0 from 'F' and 'E' and 'U'
10078e85 281 //vout.0: funding CC change
282 //vout.1: normal output to unlock address
283 //vout.n-1: opreturn 'U' sbits fundingtxid
284 for (i=0; i<numvins; i++)
285 {
286 if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 )
287 return eval->Invalid("unexpected normal vin for unlock");
288 }
289 if ( DiceExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue) == 0 )
290 return false;
291 else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 )
292 return eval->Invalid("always should find vin.0, but didnt");
293 else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
294 return eval->Invalid("lock tx vout.0 is normal output");
295 else if ( tx.vout.size() < 3 )
296 return eval->Invalid("unlock tx not enough vouts");
297 else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
298 return eval->Invalid("unlock tx vout.0 is normal output");
299 else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 )
300 return eval->Invalid("unlock tx vout.1 is CC output");
301 else if ( tx.vout[1].scriptPubKey != vinTx.vout[1].scriptPubKey )
302 return eval->Invalid("unlock tx vout.1 mismatched scriptPubKey");
303 amount = vinTx.vout[0].nValue;
98c6e2e1 304 reward = 0;
305 //reward = DiceCalc(amount,tx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks);
10078e85 306 if ( tx.vout[1].nValue > amount+reward )
307 return eval->Invalid("unlock tx vout.1 isnt amount+reward");
308 preventCCvouts = 1;
309 break;
cfea7a46 310 }
311 }
10078e85 312 return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts));
cfea7a46 313 }
10078e85 314 return(true);
cfea7a46 315}
cfea7a46 316
28b947b8 317// 'B' vs 'F' and 'E'
10078e85 318uint64_t AddDiceInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs)
cfea7a46 319{
72362bbe 320 char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hash,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid;
cfea7a46 321 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
322 GetCCaddress(cp,coinaddr,pk);
323 SetCCunspents(unspentOutputs,coinaddr);
324 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
325 {
326 txid = it->first.txhash;
10078e85 327 vout = (int32_t)it->first.index;
328 fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
329 for (j=0; j<mtx.vin.size(); j++)
330 if ( txid == mtx.vin[j].prevout.hash && vout == mtx.vin[j].prevout.n )
331 break;
332 if ( j != mtx.vin.size() )
333 continue;
334 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
cfea7a46 335 {
72362bbe 336 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash)) != 0 )
cfea7a46 337 {
10078e85 338 fprintf(stderr,"fundsflag.%d (%c) %.8f %.8f\n",fundsflag,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN);
28b947b8 339 if ( fundsflag != 0 && funcid != 'F' && funcid != 'E' && funcid != 'U' )
10078e85 340 continue;
04cf9f60 341 else if ( fundsflag == 0 && (funcid != 'B' || tx.vout.size() < 4) )
10078e85 342 continue;
cfea7a46 343 if ( total != 0 && maxinputs != 0 )
10078e85 344 {
345 if ( fundsflag == 0 )
346 scriptPubKey = tx.vout[1].scriptPubKey;
347 mtx.vin.push_back(CTxIn(txid,vout,CScript()));
348 }
349 totalinputs += it->second.satoshis;
cfea7a46 350 n++;
351 if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
352 break;
10078e85 353 } else fprintf(stderr,"null funcid\n");
cfea7a46 354 }
355 }
356 return(totalinputs);
357}
358
04cf9f60 359uint64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid)
10078e85 360{
04cf9f60 361 char coinaddr[64]; uint64_t sbits,nValue,totalinputs = 0; uint256 hash,txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout,first=0; uint8_t funcid;
10078e85 362 std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
363 GetCCaddress(cp,coinaddr,pk);
364 SetCCunspents(unspentOutputs,coinaddr);
04cf9f60 365 entropyval = 0;
10078e85 366 for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
367 {
368 txid = it->first.txhash;
369 vout = (int32_t)it->first.index;
370 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 )
371 {
72362bbe 372 if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash)) != 0 )
10078e85 373 {
374 if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid )
375 {
376 if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 0 )
04cf9f60 377 {
10078e85 378 totalinputs += nValue;
35d43add 379 fprintf(stderr,"add %.8f\n",(double)nValue/COIN);
28b947b8 380 if ( first == 0 && funcid == 'E' )
04cf9f60 381 {
382 entropytxid = txid;
383 entropyval = tx.vout[0].nValue;
384 first = 1;
385 }
386 }
10078e85 387 else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN);
35d43add 388 } else fprintf(stderr,"else case funcid %d\n",funcid);
10078e85 389 } else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN);
390 }
391 }
392 return(totalinputs);
393}
394
d0d96ab0 395bool DicePlanExists(struct CCcontract_info *cp,uint64_t refsbits,CPubKey dicepk,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &forfeitblocks)
10078e85 396{
397 char CCaddr[64]; uint64_t sbits; uint256 txid,hashBlock; CTransaction tx;
398 std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
399 GetCCaddress(cp,CCaddr,dicepk);
400 SetCCtxids(txids,CCaddr);
401 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
402 {
403 //int height = it->first.blockHeight;
404 txid = it->first.txhash;
405 if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 )
406 {
d0d96ab0 407 if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 'F' )
10078e85 408 {
409 if ( sbits == refsbits )
410 return(true);
411 }
412 }
413 }
414 return(false);
415}
416
417UniValue DiceInfo(uint256 diceid)
418{
d0d96ab0 419 UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; int64_t minbet,maxbet,maxodds,forfeitblocks; uint64_t sbits; char str[67],numstr[65];
10078e85 420 if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 )
421 {
422 fprintf(stderr,"cant find fundingtxid\n");
423 result.push_back(Pair("error","cant find fundingtxid"));
424 return(result);
425 }
d0d96ab0 426 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 0 )
10078e85 427 {
428 fprintf(stderr,"fundingtxid isnt dice creation txid\n");
429 result.push_back(Pair("error","fundingtxid isnt dice creation txid"));
430 return(result);
431 }
432 result.push_back(Pair("result","success"));
433 result.push_back(Pair("fundingtxid",uint256_str(str,diceid)));
434 unstringbits(str,sbits);
435 result.push_back(Pair("name",str));
436 result.push_back(Pair("sbits",sbits));
d0d96ab0 437 sprintf(numstr,"%.8f",(double)minbet/COIN);
438 result.push_back(Pair("minbet",numstr));
439 sprintf(numstr,"%.8f",(double)maxbet/COIN);
440 result.push_back(Pair("maxbet",numstr));
441 result.push_back(Pair("maxodds",maxodds));
442 result.push_back(Pair("forfeitblocks",forfeitblocks));
10078e85 443 sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
444 result.push_back(Pair("funding",numstr));
445 return(result);
446}
447
448UniValue DiceList()
cfea7a46 449{
d0d96ab0 450 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,forfeitblocks; char str[65];
10078e85 451 cp = CCinit(&C,EVAL_DICE);
452 SetCCtxids(addressIndex,cp->normaladdr);
453 for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++)
454 {
455 txid = it->first.txhash;
456 if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
457 {
d0d96ab0 458 if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 0 )
10078e85 459 {
460 result.push_back(uint256_str(str,txid));
461 }
462 }
463 }
464 return(result);
465}
466
d0d96ab0 467std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks)
10078e85 468{
d0d96ab0 469 CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C;
0e84bf92 470 if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || forfeitblocks < 0 || forfeitblocks > 1440 )
10078e85 471 {
472 fprintf(stderr,"negative parameter error\n");
473 return(0);
474 }
cfea7a46 475 cp = CCinit(&C,EVAL_DICE);
476 if ( txfee == 0 )
477 txfee = 10000;
10078e85 478 mypk = pubkey2pk(Mypubkey());
cfea7a46 479 dicepk = GetUnspendable(cp,0);
10078e85 480 sbits = stringbits(planstr);
481 if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) != 0 )
482 {
483 fprintf(stderr,"Dice plan (%s) already exists\n",planstr);
484 return(0);
485 }
486 if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 )
487 {
488 mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk));
489 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG));
d0d96ab0 490 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,forfeitblocks)));
10078e85 491 }
492 fprintf(stderr,"cant find enough inputs\n");
493 return(0);
494}
495
496std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount)
497{
8138fad2 498 CMutableTransaction mtx; uint256 entropy,hentropy; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C;
10078e85 499 if ( amount < 0 )
500 {
501 fprintf(stderr,"negative parameter error\n");
502 return(0);
503 }
504 cp = CCinit(&C,EVAL_DICE);
505 if ( txfee == 0 )
506 txfee = 10000;
cfea7a46 507 mypk = pubkey2pk(Mypubkey());
10078e85 508 dicepk = GetUnspendable(cp,0);
509 sbits = stringbits(planstr);
510 if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) == 0 )
511 {
512 fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
513 return(0);
514 }
515 sbits = stringbits(planstr);
0d4cfd0b 516 if ( AddNormalinputs(mtx,mypk,amount+2*txfee,64) > 0 )
10078e85 517 {
8138fad2 518 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
10078e85 519 mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk));
0d4cfd0b 520 mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
28b947b8 521 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('E',sbits,fundingtxid,hentropy)));
10078e85 522 } else fprintf(stderr,"cant find enough inputs\n");
523 fprintf(stderr,"cant find fundingtxid\n");
cfea7a46 524 return(0);
525}
526
d0d96ab0 527std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds)
cfea7a46 528{
04cf9f60 529 CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits,entropyval; int64_t funding,minbet,maxbet,maxodds,forfeitblocks; uint256 entropytxid,entropy,hentropy; struct CCcontract_info *cp,C;
c857567a 530 if ( bet < 0 || odds < 1 )
10078e85 531 {
532 fprintf(stderr,"negative parameter error\n");
533 return(0);
534 }
cfea7a46 535 cp = CCinit(&C,EVAL_DICE);
536 if ( txfee == 0 )
537 txfee = 10000;
538 mypk = pubkey2pk(Mypubkey());
539 dicepk = GetUnspendable(cp,0);
10078e85 540 sbits = stringbits(planstr);
d0d96ab0 541 if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 )
cfea7a46 542 {
10078e85 543 fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
544 return(0);
545 }
be7a410a 546 if ( bet < minbet || bet > maxbet || odds > maxodds )
10078e85 547 {
be7a410a 548 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);
10078e85 549 return(0);
550 }
04cf9f60 551 if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid)) >= bet*odds+txfee && entropyval != 0 )
10078e85 552 {
0d4cfd0b 553 mtx.vin.push_back(CTxIn(entropytxid,0,CScript()));
98c6e2e1 554 if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 )
10078e85 555 {
8138fad2 556 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
04cf9f60 557 mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk));
3f9f8229 558 mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk));
98c6e2e1 559 mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
28b947b8 560 return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('B',sbits,fundingtxid,entropy)));
3f9f8229 561 } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN);
cfea7a46 562 }
04cf9f60 563 if ( entropyval == 0 && funding != 0 )
564 fprintf(stderr,"cant find dice entropy inputs\n");
565 else fprintf(stderr,"cant find dice inputs\n");
cfea7a46 566 return(0);
567}
568
10078e85 569std::string DiceUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid)
570{
5db44aff 571 int32_t houseflag = 1;
8138fad2 572 CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,dicepk; CScript opret,scriptPubKey,ignore; uint256 hashBlock,entropy,hentropy; uint64_t funding,sbits,reward=0,amount=0,inputs,CCchange=0; int64_t minbet,maxbet,maxodds,forfeitblocks; struct CCcontract_info *cp,C;
10078e85 573 cp = CCinit(&C,EVAL_DICE);
574 if ( txfee == 0 )
575 txfee = 10000;
576 dicepk = GetUnspendable(cp,0);
577 mypk = pubkey2pk(Mypubkey());
578 sbits = stringbits(planstr);
d0d96ab0 579 if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 )
10078e85 580 {
581 fprintf(stderr,"Dice plan %s doesnt exist\n",planstr);
582 return(0);
583 }
584 // need to deal with finding the right utxos
585 if ( locktxid == zeroid )
586 amount = AddDiceInputs(scriptPubKey,0,cp,mtx,dicepk,(1LL << 30),1);
587 else
588 {
589 GetCCaddress(cp,coinaddr,dicepk);
590 if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 )
591 {
592 fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr);
593 return(0);
594 }
595 if ( GetTransaction(locktxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
596 {
597 scriptPubKey = tx.vout[1].scriptPubKey;
598 mtx.vin.push_back(CTxIn(locktxid,0,CScript()));
599 }
600 else
601 {
602 fprintf(stderr,"%s no normal vout.1 in locktxid\n",coinaddr);
603 return(0);
604 }
605 }
98c6e2e1 606 reward = 0;//DiceCalc(amount,mtx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks);
607 if ( amount > 0 && reward > txfee && scriptPubKey.size() > 0 )
10078e85 608 {
609 if ( (inputs= AddDiceInputs(ignore,1,cp,mtx,dicepk,reward+txfee,30)) > 0 )
610 {
611 if ( inputs >= (reward + 2*txfee) )
612 CCchange = (inputs - (reward + txfee));
613 fprintf(stderr,"inputs %.8f CCchange %.8f amount %.8f reward %.8f\n",(double)inputs/COIN,(double)CCchange/COIN,(double)amount/COIN,(double)reward/COIN);
8138fad2 614 if ( houseflag != 0 )
615 hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash);
616 else hentropy = zeroid;
10078e85 617 mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk));
618 mtx.vout.push_back(CTxOut(amount+reward,scriptPubKey));
8138fad2 619 return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,EncodeDiceOpRet('U',sbits,fundingtxid,hentropy)));
10078e85 620 }
621 fprintf(stderr,"cant find enough dice inputs\n");
622 }
623 fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN);
624 return(0);
625}
cfea7a46 626
This page took 0.130382 seconds and 4 git commands to generate.