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