diff --git a/src/Makefile.am b/src/Makefile.am index a44839781..8b10c06e0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -266,7 +266,7 @@ libbitcoin_server_a_SOURCES = \ cc/rewards.cpp \ cc/dice.cpp \ cc/lotto.cpp \ - cc/ponzi.cpp \ + cc/fsm.cpp \ cc/auction.cpp \ cc/betprotocol.cpp \ chain.cpp \ diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 2a9e376c0..22ca71c66 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -461,7 +461,9 @@ std::string FillSell(int64_t txfee,uint256 assetid,uint256 assetid2,uint256 askt CCchange = (inputs - paid_nValue); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,orig_assetoshis - received_assetoshis,GetUnspendable(cp,0))); mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,received_assetoshis,mypk)); - mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG)); + if ( assetid2 != zeroid ) + mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,paid_nValue,origpubkey)); + else mtx.vout.push_back(CTxOut(paid_nValue,CScript() << origpubkey << OP_CHECKSIG)); if ( CCchange != 0 ) mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,CCchange,mypk)); return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,EncodeAssetOpRet(assetid2!=zeroid?'E':'S',assetid,assetid2,remaining_nValue,origpubkey))); diff --git a/src/cc/CCcustom.cpp b/src/cc/CCcustom.cpp index 2b1c83b20..9bf1d5449 100644 --- a/src/cc/CCcustom.cpp +++ b/src/cc/CCcustom.cpp @@ -20,7 +20,7 @@ #include "CCdice.h" #include "CCauction.h" #include "CClotto.h" -#include "CCponzi.h" +#include "CCfsm.h" /* CCcustom has most of the functions that need to be extended to create a new CC contract. @@ -106,13 +106,13 @@ uint8_t LottoCCpriv[32] = { 0xb4, 0xac, 0xc2, 0xd9, 0x67, 0x34, 0xd7, 0x58, 0x80 #undef FUNCNAME #undef EVALCODE -// Ponzi -#define FUNCNAME IsPonziInput -#define EVALCODE EVAL_PONZI -const char *PonziCCaddr = "RUKTbLBeKgHkm3Ss4hKZP3ikuLW1xx7B2x"; -const char *PonziNormaladdr = "RWSHRbxnJYLvDjpcQ2i8MekgP6h2ctTKaj"; -char PonziCChexstr[67] = { "039b52d294b413b07f3643c1a28c5467901a76562d8b39a785910ae0a0f3043810" }; -uint8_t PonziCCpriv[32] = { 0x11, 0xe1, 0xea, 0x3e, 0xdb, 0x36, 0xf0, 0xa8, 0xc6, 0x34, 0xe1, 0x21, 0xb8, 0x02, 0xb9, 0x4b, 0x12, 0x37, 0x8f, 0xa0, 0x86, 0x23, 0x50, 0xb2, 0x5f, 0xe4, 0xe7, 0x36, 0x0f, 0xda, 0xae, 0xfc }; +// Finite State Machine +#define FUNCNAME IsFSMInput +#define EVALCODE EVAL_FSM +const char *FSMCCaddr = "RUKTbLBeKgHkm3Ss4hKZP3ikuLW1xx7B2x"; +const char *FSMNormaladdr = "RWSHRbxnJYLvDjpcQ2i8MekgP6h2ctTKaj"; +char FSMCChexstr[67] = { "039b52d294b413b07f3643c1a28c5467901a76562d8b39a785910ae0a0f3043810" }; +uint8_t FSMCCpriv[32] = { 0x11, 0xe1, 0xea, 0x3e, 0xdb, 0x36, 0xf0, 0xa8, 0xc6, 0x34, 0xe1, 0x21, 0xb8, 0x02, 0xb9, 0x4b, 0x12, 0x37, 0x8f, 0xa0, 0x86, 0x23, 0x50, 0xb2, 0x5f, 0xe4, 0xe7, 0x36, 0x0f, 0xda, 0xae, 0xfc }; #include "CCcustom.inc" #undef FUNCNAME #undef EVALCODE @@ -173,13 +173,13 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp,uint8_t evalcode) cp->validate = LottoValidate; cp->ismyvin = IsLottoInput; break; - case EVAL_PONZI: - strcpy(cp->unspendableCCaddr,PonziCCaddr); - strcpy(cp->normaladdr,PonziNormaladdr); - strcpy(cp->CChexstr,PonziCChexstr); - memcpy(cp->CCpriv,PonziCCpriv,32); - cp->validate = PonziValidate; - cp->ismyvin = IsPonziInput; + case EVAL_FSM: + strcpy(cp->unspendableCCaddr,FSMCCaddr); + strcpy(cp->normaladdr,FSMNormaladdr); + strcpy(cp->CChexstr,FSMCChexstr); + memcpy(cp->CCpriv,FSMCCpriv,32); + cp->validate = FSMValidate; + cp->ismyvin = IsFSMInput; break; case EVAL_AUCTION: strcpy(cp->unspendableCCaddr,AuctionCCaddr); diff --git a/src/cc/CCdice.h b/src/cc/CCdice.h index 23adb0ffb..16b2f6136 100644 --- a/src/cc/CCdice.h +++ b/src/cc/CCdice.h @@ -24,7 +24,9 @@ bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds); -std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks); +std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout); +double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid); +std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks); std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount); UniValue DiceInfo(uint256 diceid); UniValue DiceList(); diff --git a/src/cc/CCfaucet.h b/src/cc/CCfaucet.h index b478165b5..b875bd133 100644 --- a/src/cc/CCfaucet.h +++ b/src/cc/CCfaucet.h @@ -26,5 +26,6 @@ bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx // CCcustom std::string FaucetFund(uint64_t txfee,uint64_t funds); std::string FaucetGet(uint64_t txfee); +UniValue FaucetInfo(); #endif diff --git a/src/cc/CCponzi.h b/src/cc/CCfsm.h similarity index 80% rename from src/cc/CCponzi.h rename to src/cc/CCfsm.h index eb28737f7..c6ea17024 100644 --- a/src/cc/CCponzi.h +++ b/src/cc/CCfsm.h @@ -14,16 +14,17 @@ ******************************************************************************/ -#ifndef CC_PONZI_H -#define CC_PONZI_H +#ifndef CC_FSM_H +#define CC_FSM_H #include "CCinclude.h" -#define EVAL_PONZI 0xe7 +#define EVAL_FSM 0xe7 -bool PonziValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); -std::string PonziBuy(uint64_t txfee,uint64_t amount); -std::string PonziClaim(uint64_t txfee); +std::string FSMList(); +std::string FSMInfo(uint256 fsmtxid); +std::string FSMCreate(uint64_t txfee,std::string name,std::string states); #endif diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index b7186e317..f10027c97 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -30,6 +30,8 @@ #define SMALLVAL 0.000000000000001 +union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; +typedef union _bits256 bits256; struct CCcontract_info { @@ -47,7 +49,14 @@ extern CWallet* pwalletMain; #endif bool GetAddressUnspent(uint160 addressHash, int type,std::vector > &unspentOutputs); -static uint256 zeroid; +static const uint256 zeroid; +bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock); +int32_t is_hexstr(char *str,int32_t n); +bool myAddtomempool(CTransaction &tx); +//uint64_t myGettxout(uint256 hash,int32_t n); +bool myIsutxo_spentinmempool(uint256 txid,int32_t vout); +int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout); +bool mySendrawtransaction(std::string res); // CCcustom CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv); @@ -79,4 +88,10 @@ void SetCCtxids(std::vector > &addressIndex uint64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,uint64_t total,int32_t maxinputs); uint64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout); +// curve25519 and sha256 +bits256 curve25519_shared(bits256 privkey,bits256 otherpub); +bits256 curve25519_basepoint9(); +bits256 curve25519(bits256 mysecret,bits256 basepoint); +void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len); + #endif diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index c20a579f1..bea26e4a2 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -52,7 +52,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran if ( (n= mtx.vin.size()) > 64 ) { fprintf(stderr,"FinalizeCCTx: %d is too many vins\n",n); - return(0); + return("0"); } Myprivkey(myprivkey); unspendablepk = GetUnspendable(cp,unspendablepriv); @@ -82,7 +82,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran } else fprintf(stderr,"FinalizeCCTx couldnt find %s\n",mtx.vin[i].prevout.hash.ToString().c_str()); } nmask = (1LL << n) - 1; - if ( (mask & nmask) != (CCmask & nmask) ) + if ( 0 && (mask & nmask) != (CCmask & nmask) ) fprintf(stderr,"mask.%llx vs CCmask.%llx %llx %llx %llx\n",(long long)(mask & nmask),(long long)(CCmask & nmask),(long long)mask,(long long)CCmask,(long long)nmask); if ( totalinputs >= totaloutputs+2*txfee ) { @@ -147,7 +147,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran std::string strHex = EncodeHexTx(mtx); if ( strHex.size() > 0 ) return(strHex); - else return(0); + else return("0"); } void SetCCunspents(std::vector > &unspentOutputs,char *coinaddr) @@ -203,7 +203,7 @@ uint64_t CCutxovalue(char *coinaddr,uint256 utxotxid,int32_t utxovout) uint64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,uint64_t total,int32_t maxinputs) { - int32_t vout,j,n = 0; uint64_t nValue,totalinputs = 0; uint256 txid; std::vector vecOutputs; + int32_t vout,j,n = 0; uint64_t nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector vecOutputs; CTransaction tx; #ifdef ENABLE_WALLET const CKeyStore& keystore = *pwalletMain; assert(pwalletMain != NULL); @@ -220,12 +220,15 @@ uint64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,uint64_t total,in break; if ( j != mtx.vin.size() ) continue; - mtx.vin.push_back(CTxIn(txid,vout,CScript())); - nValue = out.tx->vout[out.i].nValue; - totalinputs += nValue; - n++; - if ( totalinputs >= total || n >= maxinputs ) - break; + if ( myIsutxo_spentinmempool(txid,vout) == 0 ) + { + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + nValue = out.tx->vout[out.i].nValue; + totalinputs += nValue; + n++; + if ( totalinputs >= total || n >= maxinputs ) + break; + } } } if ( totalinputs >= total ) diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 632b243bc..fff113d30 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -193,7 +193,10 @@ bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t n for (i=preventCCvouts; iInvalid("invalid CC vout"); + } } } return(true); @@ -252,26 +255,30 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv) bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector paramsNull,const CTransaction &ctx, unsigned int nIn) { - CTransaction createTx; uint256 txid,assetid,assetid2,hashBlock; uint8_t funcid; int32_t i,n; uint64_t amount; std::vector origpubkey; - txid = ctx.GetHash(); - if ( txid == cp->prevtxid ) - return(true); + CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t i,n; uint64_t amount; std::vector origpubkey; + // there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example + //txid = ctx.GetHash(); + //if ( txid == cp->prevtxid ) + // return(true); + //fprintf(stderr,"process CC %02x\n",cp->evalcode); if ( paramsNull.size() != 0 ) // Don't expect params return eval->Invalid("Cannot have params"); else if ( ctx.vout.size() == 0 ) return eval->Invalid("no-vouts"); else if ( (*cp->validate)(cp,eval,ctx) != 0 ) { - cp->prevtxid = txid; + //fprintf(stderr,"done CC %02x\n",cp->evalcode); + //cp->prevtxid = txid; return(true); } + //fprintf(stderr,"invalid CC %02x\n",cp->evalcode); return(false); } int64_t CCduration(uint256 txid) { CTransaction tx; uint256 hashBlock; uint32_t txtime=0; char str[65]; CBlockIndex *pindex; int64_t duration = 0; - if ( GetTransaction(txid,tx,hashBlock,false) == 0 ) + if ( myGetTransaction(txid,tx,hashBlock) == 0 ) { fprintf(stderr,"CCduration cant find duration txid %s\n",uint256_str(str,txid)); return(0); diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 1deb330f9..2088d9b73 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -252,19 +252,27 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx break; case 's': // selloffer - case 'e': // exchange + case 'e': // selloffer //vin.0: normal input //vin.1+: valid CC output for sale //vout.0: vin.1 assetoshis output to CC to unspendable - //vout.1: normal output for change (if any) + //vout.1: CC output for change (if any) + //vout.2: normal output for change (if any) //'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey] //'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey] + preventCCvouts = 1; if ( remaining_price == 0 ) return eval->Invalid("illegal null remaining_price for selloffer"); - else if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,inputs) == 0 ) + if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + preventCCvouts++; + if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,0) == 0 ) + return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); + else if ( tx.vout[0].nValue+tx.vout[1].nValue != inputs ) + return eval->Invalid("mismatched vout0+vout1 total for selloffer"); + } else if ( ConstrainVout(tx.vout[0],1,(char *)cp->unspendableCCaddr,inputs) == 0 ) return eval->Invalid("mismatched vout0 AssetsCCaddr for selloffer"); //fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price); - preventCCvouts = 1; break; case 'x': // cancel @@ -341,7 +349,10 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx if ( ConstrainVout(tx.vout[2],1,CCaddr,0) == 0 ) return eval->Invalid("vout2 doesnt go to origpubkey fillex"); else if ( inputs != tx.vout[2].nValue+tx.vout[3].nValue ) + { + fprintf(stderr,"inputs %.8f != %.8f + %.8f\n",(double)inputs/COIN,(double)tx.vout[2].nValue/COIN,(double)tx.vout[3].nValue/COIN); return eval->Invalid("asset inputs doesnt match vout2+3 fillex"); + } } else if ( ConstrainVout(tx.vout[2],1,CCaddr,inputs) == 0 ) return eval->Invalid("vout2 doesnt match inputs fillex"); diff --git a/src/cc/auction.cpp b/src/cc/auction.cpp index 1bcf2ecd8..cf3ae601a 100644 --- a/src/cc/auction.cpp +++ b/src/cc/auction.cpp @@ -127,6 +127,8 @@ uint64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP { txid = it->first.txhash; // prevent dup + if ( it->second.satoshis < 1000000 ) + continue; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { if ( (nValue= IsAuctionvout(cp,vintx,(int32_t)it->first.index)) > 0 ) diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index 0e6669964..68c3e6cc7 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -15,45 +15,253 @@ #include "CCdice.h" +// timeout + /* in order to implement a dice game, we need a source of entropy, reasonably fast completion time and a way to manage the utxos. - 1. CC vout locks "house" funds with hash(entropy) + half of shared secret + 1. CC vout locks "house" funds with hash(entropy) 2. bettor submits bet, with entropy, odds, houseid and sends combined amount into another CC vout. - 3. house account sends funds to winner with proof of entropy - 4. if timeout, bettor wins funds + 3. house account sends funds to winner/loser with proof of entropy + 4. if timeout, bettor gets refund 2. and 3. can be done in mempool + + The house commits to an entropy value by including the hash of the entropy value in the 'E' transaction. + + 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. + + 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. + + 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 + + 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. + +createfunding: + vins.*: normal inputs + vout.0: CC vout for funding + vout.1: owner vout + vout.2: dice marker address vout for easy searching + vout.3: normal change + vout.n-1: opreturn 'F' sbits minbet maxbet maxodds timeoutblocks + +addfunding (entropy): + vins.*: normal inputs + vout.0: CC vout for locked entropy funds + vout.1: tag to owner address for entropy funds + vout.2: normal change + vout.n-1: opreturn 'E' sbits fundingtxid hentropy + +bet: + vin.0: entropy txid from house (must validate vin0 of 'E') + vins.1+: normal inputs + vout.0: CC vout for locked entropy + vout.1: CC vout for locked bet + vout.2: tag for bettor's address (txfee + odds) + vout.3: change + vout.n-1: opreturn 'B' sbits fundingtxid entropy + +loser: + vin.0: normal input + vin.1: betTx CC vout.0 entropy from bet + vin.2: betTx CC vout.1 bet amount from bet + vin.3+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T' + vout.0: funding CC to entropy owner + vout.1: tag to owner address for entropy funds + vout.2: change to fundingpk + vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof + +winner: + same as loser, but vout.2 is winnings + vout.3: change to fundingpk + vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof + +timeout: + same as winner, just without hentropy or proof + */ -uint64_t DiceCalc(uint64_t amount,uint256 txid,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks) +#include "../endian.h" + +static uint256 bettxids[128]; + +struct dicefinish_info { - /*uint64_t duration,reward = 0; - if ( (duration= CCduration(txid)) < minseconds ) + uint256 fundingtxid,bettxid; + uint64_t sbits; + int32_t iswin; +}; + +bool mySendrawtransaction(std::string res) +{ + CTransaction tx; char str[65]; + if ( res.empty() == 0 && res.size() > 64 && is_hexstr((char *)res.c_str(),0) > 64 ) { - return(0); - //duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24); - } else if ( duration > maxseconds ) - maxseconds = duration; - reward = (((amount * APR) / COIN) * duration) / (365*24*3600LL * 100); - fprintf(stderr,"amount %.8f %.8f %llu -> duration.%llu reward %.8f\n",(double)amount/COIN,((double)amount * APR)/COIN,(long long)((amount * APR) / (COIN * 365*24*3600)),(long long)duration,(double)reward/COIN); - return(reward);*/ + if ( DecodeHexTx(tx,res) != 0 ) + { + fprintf(stderr,"%s\n%s\n",res.c_str(),uint256_str(str,tx.GetHash())); + LOCK(cs_main); + if ( myAddtomempool(tx) != 0 ) + { + RelayTransaction(tx); + fprintf(stderr,"added to mempool and broadcast\n"); + return(true); + } else fprintf(stderr,"error adding to mempool\n"); + } else fprintf(stderr,"error decoding hex\n"); + } + return(false); +} + +void *dicefinish(void *_ptr) +{ + char str[65],str2[65],name[32]; std::string res; int32_t i,result,duplicate=0; struct dicefinish_info *ptr; + ptr = (struct dicefinish_info *)_ptr; + sleep(3); // wait for bettxid to be in mempool + for (i=0; ibettxid ) + { + duplicate = 1; + break; + } + if ( duplicate == 0 ) + { + for (i=0; ibettxid; + break; + } + if ( i == sizeof(bettxids)/sizeof(*bettxids) ) + bettxids[rand() % i] = ptr->bettxid; + } + unstringbits(name,ptr->sbits); + //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)); + if ( duplicate == 0 ) + { + res = DiceBetFinish(&result,0,name,ptr->fundingtxid,ptr->bettxid,ptr->iswin); + if ( result > 0 ) + mySendrawtransaction(res); + } + free(ptr); return(0); } -CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks) +void DiceQueue(int32_t iswin,uint64_t sbits,uint256 fundingtxid,uint256 bettxid) +{ + struct dicefinish_info *ptr = (struct dicefinish_info *)calloc(1,sizeof(*ptr)); + ptr->fundingtxid = fundingtxid; + ptr->bettxid = bettxid; + ptr->sbits = sbits; + ptr->iswin = iswin; + if ( ptr != 0 && pthread_create((pthread_t *)malloc(sizeof(pthread_t)),NULL,dicefinish,(void *)ptr) != 0 ) + { + //fprintf(stderr,"DiceQueue.%d\n",iswin); + } // small memory leak per DiceQueue +} + +void endiancpy(uint8_t *dest,uint8_t *src,int32_t len) +{ + int32_t i,j=0; +#if defined(WORDS_BIGENDIAN) + for (i=31; i>=0; i--) + dest[j++] = src[i]; +#else + memcpy(dest,src,len); +#endif +} + +CPubKey DiceFundingPk(CScript scriptPubKey) +{ + CPubKey pk; uint8_t *ptr,*dest; int32_t i; + if ( scriptPubKey.size() == 35 ) + { + ptr = (uint8_t *)scriptPubKey.data(); + dest = (uint8_t *)pk.begin(); + for (i=0; i<33; i++) + dest[i] = ptr[i+1]; + } else fprintf(stderr,"DiceFundingPk invalid size.%d\n",(int32_t)scriptPubKey.size()); + return(pk); +} + +uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv) // max 1 vout per txid used +{ + int32_t i; uint8_t _entropy[32],_hentropy[32]; bits256 tmp256,txidpub,txidpriv,mypriv,mypub,ssecret,ssecret2; uint256 hentropy; + memset(&hentropy,0,32); + endiancpy(txidpriv.bytes,(uint8_t *)&_txidpriv,32); + txidpriv.bytes[0] &= 0xf8, txidpriv.bytes[31] &= 0x7f, txidpriv.bytes[31] |= 0x40; + txidpub = curve25519(txidpriv,curve25519_basepoint9()); + + Myprivkey(tmp256.bytes); + vcalc_sha256(0,mypriv.bytes,tmp256.bytes,32); + mypriv.bytes[0] &= 0xf8, mypriv.bytes[31] &= 0x7f, mypriv.bytes[31] |= 0x40; + mypub = curve25519(mypriv,curve25519_basepoint9()); + + ssecret = curve25519(mypriv,txidpub); + ssecret2 = curve25519(txidpriv,mypub); + if ( memcmp(ssecret.bytes,ssecret2.bytes,32) == 0 ) + { + vcalc_sha256(0,(uint8_t *)&_entropy,ssecret.bytes,32); + vcalc_sha256(0,(uint8_t *)&_hentropy,_entropy,32); + endiancpy((uint8_t *)&entropy,_entropy,32); + endiancpy((uint8_t *)&hentropy,_hentropy,32); + } + else + { + for (i=0; i<32; i++) + fprintf(stderr,"%02x",ssecret.bytes[i]); + fprintf(stderr," ssecret\n"); + for (i=0; i<32; i++) + fprintf(stderr,"%02x",ssecret2.bytes[i]); + fprintf(stderr," ssecret2 dont match\n"); + } + //char str[65],str2[65]; + //fprintf(stderr,"generated house hentropy.%s <- entropy.%s\n",uint256_str(str,hentropy),uint256_str(str2,entropy)); + return(hentropy); +} + +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) +{ + uint8_t buf[64],_house[32],_bettor[32]; uint64_t winnings; arith_uint256 house,bettor; char str[65],str2[65]; + if ( odds < 10000 ) + return(0); + else odds -= 10000; + if ( bet < minbet || bet > maxbet || odds > maxodds ) + { + fprintf(stderr,"bet size violation %.8f\n",(double)bet/COIN); + return(0); + } + //fprintf(stderr,"calc house entropy %s vs bettor %s\n",uint256_str(str,houseentropy),uint256_str(str2,bettorentropy)); + + endiancpy(buf,(uint8_t *)&houseentropy,32); + endiancpy(&buf[32],(uint8_t *)&bettorentropy,32); + vcalc_sha256(0,(uint8_t *)&_house,buf,64); + endiancpy((uint8_t *)&house,_house,32); + + endiancpy(buf,(uint8_t *)&bettorentropy,32); + endiancpy(&buf[32],(uint8_t *)&houseentropy,32); + vcalc_sha256(0,(uint8_t *)&_bettor,buf,64); + endiancpy((uint8_t *)&bettor,_bettor,32); + if ( odds > 1 ) + bettor = (bettor / arith_uint256(odds)); + if ( bettor >= house ) + winnings = bet * (odds+1); + else winnings = 0; + return(winnings); +} + +CScript EncodeDiceFundingOpRet(uint8_t funcid,uint64_t sbits,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks) { CScript opret; uint8_t evalcode = EVAL_DICE; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << forfeitblocks); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'F' << sbits << minbet << maxbet << maxodds << timeoutblocks); return(opret); } -uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &forfeitblocks) +uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64_t &minbet,int64_t &maxbet,int64_t &maxodds,int64_t &timeoutblocks) { std::vector vopret; uint8_t *script,e,f; GetOpReturnData(scriptPubKey, vopret); script = (uint8_t *)vopret.data(); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 0 ) + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 ) { if ( e == EVAL_DICE && f == 'F' ) return(f); @@ -61,17 +269,17 @@ uint8_t DecodeDiceFundingOpRet(const CScript &scriptPubKey,uint64_t &sbits,int64 return(0); } -CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid) +CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid,uint256 hash,uint256 proof) { CScript opret; uint8_t evalcode = EVAL_DICE; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid); + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << sbits << fundingtxid << hash << proof); return(opret); } -uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid) +uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits,uint256 &fundingtxid,uint256 &hash,uint256 &proof) { - std::vector vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,forfeitblocks; - GetOpReturnData(scriptPubKey, vopret); + std::vector vopret; uint8_t *script,e,f,funcid; int64_t minbet,maxbet,maxodds,timeoutblocks; + GetOpReturnData(scriptPubKey,vopret); if ( vopret.size() > 2 ) { script = (uint8_t *)vopret.data(); @@ -79,15 +287,16 @@ uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits { if ( script[1] == 'F' ) { - if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> forfeitblocks) != 0 ) + if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> minbet; ss >> maxbet; ss >> maxodds; ss >> timeoutblocks) != 0 ) { + memset(&hash,0,32); fundingtxid = txid; return('F'); } else fprintf(stderr,"unmarshal error for F\n"); } - else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid) != 0 ) + else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid; ss >> hash; ss >> proof) != 0 ) { - if ( e == EVAL_DICE && (f == 'L' || f == 'U' || f == 'A') ) + if ( e == EVAL_DICE && (f == 'B' || f == 'W' || f == 'L' || f == 'T' || f == 'E') ) return(f); else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f); } @@ -96,6 +305,14 @@ uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits return(0); } +uint256 DiceGetEntropy(CTransaction tx,uint8_t reffuncid) +{ + uint256 hash,fundingtxid,proof; uint64_t sbits; int32_t numvouts; + if ( (numvouts= tx.vout.size()) > 0 && DecodeDiceOpRet(tx.GetHash(),tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof) == reffuncid ) + return(hash); + else return(zeroid); +} + uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) { char destaddr[64]; @@ -107,12 +324,12 @@ uint64_t IsDicevout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) return(0); } -bool DiceExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx,uint64_t txfee) +int64_t DiceAmounts(uint64_t &inputs,uint64_t &outputs,struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) { - static uint256 zerohash; - CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis; + CTransaction vinTx; uint256 hashBlock; int32_t i,numvins,numvouts; uint64_t assetoshis; numvins = tx.vin.size(); numvouts = tx.vout.size(); + inputs = outputs = 0; for (i=0; iismyvin)(tx.vin[i].scriptSig) != 0 ) @@ -121,8 +338,6 @@ bool DiceExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction & return eval->Invalid("always should find vin, but didnt"); else { - if ( hashBlock == zerohash ) - return eval->Invalid("cant dice from mempool"); if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) inputs += assetoshis; } @@ -134,17 +349,56 @@ bool DiceExactAmounts(struct CCcontract_info *cp,Eval *eval,const CTransaction & if ( (assetoshis= IsDicevout(cp,tx,i)) != 0 ) outputs += assetoshis; } - if ( inputs != outputs+txfee ) - { - fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs); - return eval->Invalid("mismatched inputs != outputs + txfee"); - } - else return(true); + return(inputs - outputs); } -bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) +bool DiceIsmine(const CScript scriptPubKey) { - uint256 txid,fundingtxid,hashBlock; 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; + char destaddr[64],myaddr[64]; + Getscriptaddress(destaddr,scriptPubKey); + Getscriptaddress(myaddr,CScript() << Mypubkey() << OP_CHECKSIG); + return(strcmp(destaddr,myaddr) == 0); +} + +int32_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) +{ + uint64_t vinsbits,winnings; uint256 vinproof,vinfundingtxid,hentropy,hentropy2; uint8_t funcid; + //char str[65],str2[65]; + if ( vinTx.vout.size() > 1 && DiceIsmine(vinTx.vout[1].scriptPubKey) != 0 && vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( ((funcid= DecodeDiceOpRet(txid,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,hentropy,vinproof)) == 'E' || funcid == 'W' || funcid == 'L') && sbits == vinsbits && fundingtxid == vinfundingtxid ) + { + hentropy2 = DiceHashEntropy(entropy,vinTx.vin[0].prevout.hash); + if ( hentropy == hentropy2 ) + { + winnings = DiceCalc(tx.vout[1].nValue,tx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,entropy,bettorentropy); + char str[65]; fprintf(stderr,"%s winnings %.8f bet %.8f at odds %d:1\n",uint256_str(str,tx.GetHash()),(double)winnings/COIN,(double)tx.vout[1].nValue/COIN,(int32_t)(tx.vout[2].nValue-10000)); + //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); + if ( winnings == 0 ) + { + // queue 'L' losing tx + return(-1); + } + else + { + // queue 'W' winning tx + return(1); + } + } else fprintf(stderr,"hentropy != hentropy2\n"); + } else fprintf(stderr,"funcid.%c sbits %llx vs %llx cmp.%d\n",funcid,(long long)sbits,(long long)vinsbits,fundingtxid == vinfundingtxid); + } //else fprintf(stderr,"notmine or not CC\n"); + return(0); +} + +bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks) +{ + fprintf(stderr,"DiceVerifyTimeout needs to be implemented\n"); + return(false); +} + +bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) +{ + 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]; numvins = tx.vin.size(); numvouts = tx.vout.size(); preventCCvins = preventCCvouts = -1; @@ -153,12 +407,13 @@ bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) else { txid = tx.GetHash(); - if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 ) + if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 ) { if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 ) return eval->Invalid("cant find fundingtxid"); - else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 'F' ) + else if ( fundingTx.vout.size() > 0 && DecodeDiceFundingOpRet(fundingTx.vout[fundingTx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 'F' ) return eval->Invalid("fundingTx not valid"); + fundingPubKey = fundingTx.vout[1].scriptPubKey; switch ( funcid ) { case 'F': @@ -166,54 +421,142 @@ bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) //vout.0: CC vout for funding //vout.1: normal marker vout for easy searching //vout.2: normal change - //vout.n-1: opreturn 'F' sbits APR minseconds maxseconds mindeposit + //vout.n-1: opreturn 'F' sbits minbet maxbet maxodds timeoutblocks return eval->Invalid("unexpected DiceValidate for createfunding"); break; - case 'A': + case 'E': // check sig of vin to match fundingtxid in the 'B' tx //vins.*: normal inputs - //vout.0: CC vout for funding - //vout.1: normal change - //vout.n-1: opreturn 'A' sbits fundingtxid - return eval->Invalid("unexpected DiceValidate for addfunding"); + //vout.0: CC vout for locked entropy funds + //vout.1: tag to owner address for entropy funds + //vout.2: normal change + //vout.n-1: opreturn 'E' sbits fundingtxid hentropy + return eval->Invalid("unexpected DiceValidate for addfunding entropy"); + break; + case 'B': + //vin.0: entropy txid from house + //vins.1+: normal inputs + //vout.0: CC vout for locked entropy + //vout.1: CC vout for locked bet + //vout.2: tag for bettor's address (txfee + odds) + //vout.3: change + //vout.n-1: opreturn 'B' sbits fundingtxid entropy + preventCCvouts = 2; + preventCCvins = 1; + if ( IsCCInput(tx.vin[0].scriptSig) == 0 ) + return eval->Invalid("vin.0 is normal for bet"); + else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.0 is normal for bet"); + else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + return eval->Invalid("vout.1 is normal for bet"); + else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("always should find vin.0, but didnt for bet"); + else if ( vinTx.vout[1].scriptPubKey != fundingPubKey ) + return eval->Invalid("entropy tx not fundingPubKey for bet"); + else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,vinTx.vout[tx.vin[0].prevout.n].nValue) == 0 ) + return eval->Invalid("vout[0] != entropy nValue for bet"); + else if ( ConstrainVout(tx.vout[1],1,cp->unspendableCCaddr,0) == 0 ) + return eval->Invalid("vout[1] constrain violation for bet"); + else if ( tx.vout[2].nValue >= txfee+maxodds || tx.vout[2].nValue < txfee ) + return eval->Invalid("vout[2] nValue violation for bet"); + else if ( eval->GetTxUnconfirmed(vinTx.vin[0].prevout.hash,vinofvinTx,hashBlock) == 0 || vinofvinTx.vout.size() < 1 ) + return eval->Invalid("always should find vinofvin.0, but didnt for bet"); + else if ( vinTx.vin[0].prevout.hash != fundingtxid ) + { + if ( vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey != fundingPubKey ) + { + uint8_t *ptr0,*ptr1; int32_t i; char str[65]; + fprintf(stderr,"bidTx.%s\n",uint256_str(str,txid)); + fprintf(stderr,"entropyTx.%s v%d\n",uint256_str(str,tx.vin[0].prevout.hash),(int32_t)tx.vin[0].prevout.n); + fprintf(stderr,"entropyTx vin0 %s v%d\n",uint256_str(str,vinTx.vin[0].prevout.hash),(int32_t)vinTx.vin[0].prevout.n); + ptr0 = (uint8_t *)vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey.data(); + ptr1 = (uint8_t *)fundingPubKey.data(); + for (i=0; iInvalid("vin1 of entropy tx not fundingPubKey for bet"); + } + } + if ( (iswin= DiceIsWinner(entropy,txid,tx,vinTx,hash,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 ) + { + // will only happen for fundingPubKey + DiceQueue(iswin,sbits,fundingtxid,txid); + } break; case 'L': - //vins.*: normal inputs - //vout.0: CC vout for locked funds - //vout.1: normal output to unlock address - //vout.2: change - //vout.n-1: opreturn 'L' sbits fundingtxid - return eval->Invalid("unexpected DiceValidate for lock"); - break; - case 'U': - //vin.0: locked funds CC vout.0 from lock - //vin.1+: funding CC vout.0 from 'F' and 'A' and 'U' - //vout.0: funding CC change - //vout.1: normal output to unlock address - //vout.n-1: opreturn 'U' sbits fundingtxid - for (i=0; iismyvin)(tx.vin[i].scriptSig) == 0 ) - return eval->Invalid("unexpected normal vin for unlock"); - } - if ( DiceExactAmounts(cp,eval,tx,txfee+tx.vout[1].nValue) == 0 ) - return false; - else if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 ) - return eval->Invalid("always should find vin.0, but didnt"); - else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("lock tx vout.0 is normal output"); - else if ( tx.vout.size() < 3 ) - return eval->Invalid("unlock tx not enough vouts"); - else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) - return eval->Invalid("unlock tx vout.0 is normal output"); - else if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() != 0 ) - return eval->Invalid("unlock tx vout.1 is CC output"); - else if ( tx.vout[1].scriptPubKey != vinTx.vout[1].scriptPubKey ) - return eval->Invalid("unlock tx vout.1 mismatched scriptPubKey"); - amount = vinTx.vout[0].nValue; - reward = DiceCalc(amount,tx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks); - if ( tx.vout[1].nValue > amount+reward ) - return eval->Invalid("unlock tx vout.1 isnt amount+reward"); + case 'W': + case 'T': + //vin.0: normal input + //vin.1: betTx CC vout.0 entropy from bet + //vin.2: betTx CC vout.1 bet amount from bet + //vin.3+: funding CC vout.0 from 'F', 'E', 'W', 'L' or 'T' + //vout.1: tag to owner address for entropy funds preventCCvouts = 1; + DiceAmounts(inputs,outputs,cp,eval,tx); + if ( IsCCInput(tx.vin[1].scriptSig) == 0 || IsCCInput(tx.vin[2].scriptSig) == 0 ) + return eval->Invalid("vin0 or vin1 normal vin for bet"); + else if ( tx.vin[1].prevout.hash != tx.vin[2].prevout.hash ) + return eval->Invalid("vin0 != vin1 prevout.hash for bet"); + else if ( eval->GetTxUnconfirmed(tx.vin[1].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("always should find vin.0, but didnt for wlt"); + else if ( vinTx.vout.size() < 3 || DecodeDiceOpRet(tx.vin[1].prevout.hash,vinTx.vout[vinTx.vout.size()-1].scriptPubKey,vinsbits,vinfundingtxid,vinhentropy,vinproof) != 'B' ) + return eval->Invalid("not betTx for vin0/1 for wlt"); + else if ( sbits != vinsbits || fundingtxid != vinfundingtxid ) + return eval->Invalid("sbits or fundingtxid mismatch for wlt"); + else if ( fundingPubKey != tx.vout[1].scriptPubKey ) + return eval->Invalid("tx.vout[1] != fundingPubKey for wlt"); + if ( funcid == 'L' ) + { + //vout.0: funding CC to entropy owner + //vout.n-1: opreturn 'L' sbits fundingtxid hentropy proof + if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,inputs) == 0 ) + return eval->Invalid("vout[0] != inputs-txfee for loss"); + else if ( tx.vout[2].scriptPubKey != fundingPubKey ) + { + if ( tx.vout[2].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[2].scriptPubKey.data())[0] != 0x6a ) + return eval->Invalid("vout[2] not send to fundingPubKey for loss"); + } + iswin = -1; + } + else + { + //vout.0: funding CC change to entropy owner + //vout.2: normal output to bettor's address + //vout.n-1: opreturn 'W' sbits fundingtxid hentropy proof + odds = vinTx.vout[2].nValue - txfee; + if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) == 0 ) + return eval->Invalid("vout[0] != inputs-txfee for win/timeout"); + else if ( tx.vout[2].scriptPubKey != vinTx.vout[2].scriptPubKey ) + return eval->Invalid("vout[2] scriptPubKey mismatch for win/timeout"); + else if ( tx.vout[2].nValue != (odds+1)*vinTx.vout[1].nValue ) + return eval->Invalid("vout[2] payut mismatch for win/timeout"); + else if ( inputs != (outputs + tx.vout[2].nValue) && inputs != (outputs + tx.vout[2].nValue+txfee) ) + { + fprintf(stderr,"inputs %.8f != outputs %.8f + %.8f\n",(double)inputs/COIN,(double)outputs/COIN,(double)tx.vout[2].nValue/COIN); + return eval->Invalid("CC funds mismatch for win/timeout"); + } + else if ( tx.vout[3].scriptPubKey != fundingPubKey ) + { + if ( tx.vout[3].scriptPubKey.size() == 0 || ((uint8_t *)tx.vout[3].scriptPubKey.data())[0] != 0x6a ) + return eval->Invalid("vout[3] not send to fundingPubKey for win/timeout"); + } + iswin = (funcid == 'W'); + } + if ( iswin != 0 ) + { + //char str[65],str2[65]; + entropy = DiceGetEntropy(vinTx,'B'); + vcalc_sha256(0,(uint8_t *)&hash,(uint8_t *)&proof,32); + //fprintf(stderr,"calculated house hentropy.%s\n",uint256_str(str,hash)); + //fprintf(stderr,"verify house entropy %s vs bettor %s\n",uint256_str(str,proof),uint256_str(str2,entropy)); + winnings = DiceCalc(vinTx.vout[1].nValue,vinTx.vout[2].nValue,minbet,maxbet,maxodds,timeoutblocks,proof,entropy); + if ( (winnings == 0 && iswin > 0) || (winnings > 0 && iswin < 0) ) + return eval->Invalid("DiceCalc mismatch for win/loss"); + } + else if ( DiceVerifyTimeout(vinTx,timeoutblocks) == 0 ) + return eval->Invalid("invalid timeout claim for timeout"); break; } } @@ -222,10 +565,9 @@ bool DiceValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) return(true); } -// 'L' vs 'F' and 'A' -uint64_t AddDiceInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs) +uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs) { - char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t j,vout,n = 0; uint8_t funcid; + 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; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); @@ -233,95 +575,185 @@ uint64_t AddDiceInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontract { txid = it->first.txhash; vout = (int32_t)it->first.index; - fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); + if ( it->second.satoshis < 1000000 ) + continue; + //fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); for (j=0; j 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) { - if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 ) + if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 ) { - fprintf(stderr,"fundsflag.%d (%c) %.8f %.8f\n",fundsflag,funcid,(double)tx.vout[vout].nValue/COIN,(double)it->second.satoshis/COIN); - if ( fundsflag != 0 && funcid != 'F' && funcid != 'A' && funcid != 'U' ) - continue; - else if ( fundsflag == 0 && (funcid != 'L' || tx.vout.size() < 4) ) - continue; - if ( total != 0 && maxinputs != 0 ) + if ( funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T' ) { - if ( fundsflag == 0 ) - scriptPubKey = tx.vout[1].scriptPubKey; - mtx.vin.push_back(CTxIn(txid,vout,CScript())); + if ( total != 0 && maxinputs != 0 ) + mtx.vin.push_back(CTxIn(txid,vout,CScript())); + totalinputs += it->second.satoshis; + n++; + if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) + break; } - totalinputs += it->second.satoshis; - n++; - if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) - break; } else fprintf(stderr,"null funcid\n"); } } return(totalinputs); } -uint64_t DicePlanFunds(uint64_t refsbits,struct CCcontract_info *cp,CPubKey pk,uint256 reffundingtxid) +uint64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey dicepk,uint256 reffundingtxid) { - char coinaddr[64]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t vout; uint8_t funcid; + 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; std::vector > unspentOutputs; - GetCCaddress(cp,coinaddr,pk); + if ( GetTransaction(reffundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) != 0 ) + { + fundingPubKey = tx.vout[1].scriptPubKey; + } else return(0); + GetCCaddress(cp,coinaddr,dicepk); SetCCunspents(unspentOutputs,coinaddr); + entropyval = 0; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; - if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 ) { - if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 ) + //char str[65],str2[65]; + if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 ) { if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid ) { - if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 0 ) + if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout)) > 10000 && (funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T') ) + { + if ( funcid != 'F' && funcid != 'T' ) + { + n++; + fprintf(stderr,"%s.(%c %.8f) ",uint256_str(str,txid),funcid,(double)nValue/COIN); + } totalinputs += nValue; - else fprintf(stderr,"refsbits.%llx sbits.%llx nValue %.8f\n",(long long)refsbits,(long long)sbits,(double)nValue/COIN); - } //else fprintf(stderr,"else case\n"); - } else fprintf(stderr,"funcid.%d %c skipped %.8f\n",funcid,funcid,(double)tx.vout[vout].nValue/COIN); + if ( first == 0 && (funcid == 'E' || funcid == 'W' || funcid == 'L') ) + { + fprintf(stderr,"check first\n"); + if ( fundingPubKey == tx.vout[1].scriptPubKey ) + { + if ( funcid == 'E' && fundingtxid != tx.vin[0].prevout.hash ) + { + if ( GetTransaction(tx.vin[0].prevout.hash,vinTx,hashBlock,false) == 0 ) + { + 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()); + continue; + } + if ( vinTx.vout[tx.vin[0].prevout.n].scriptPubKey != fundingPubKey ) + { + uint8_t *ptr0,*ptr1; int32_t i; char str[65]; + ptr0 = (uint8_t *)vinTx.vout[tx.vin[0].prevout.n].scriptPubKey.data(); + ptr1 = (uint8_t *)fundingPubKey.data(); + for (i=0; i > txids; GetCCaddress(cp,CCaddr,dicepk); - SetCCtxids(txids,CCaddr); + SetCCtxids(txids,cp->normaladdr); + if ( fundingtxid != zeroid ) // avoid scan unless creating new funding plan + { + if ( GetTransaction(fundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 ) + { + if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' && sbits == refsbits ) + { + fundingPubKey = tx.vout[1].scriptPubKey; + return(true); + } + } + return(false); + } for (std::vector >::const_iterator it=txids.begin(); it!=txids.end(); it++) { //int height = it->first.blockHeight; txid = it->first.txhash; + if ( fundingtxid != zeroid && txid != fundingtxid ) + continue; if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 ) { - if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 'F' ) + if ( DecodeDiceFundingOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 'F' ) { if ( sbits == refsbits ) + { + fundingPubKey = tx.vout[1].scriptPubKey; + fundingtxid = txid; return(true); + } } } } return(false); } +struct 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) +{ + struct CCcontract_info *cp; int32_t cmpflag; + cp = CCinit(C,EVAL_DICE); + if ( txfee == 0 ) + txfee = 10000; + mypk = pubkey2pk(Mypubkey()); + dicepk = GetUnspendable(cp,0); + sbits = stringbits(planstr); + if ( reffundingtxid == zeroid ) + cmpflag = 0; + else cmpflag = 1; + if ( DicePlanExists(fundingPubKey,reffundingtxid,cp,sbits,dicepk,minbet,maxbet,maxodds,timeoutblocks) != cmpflag ) + { + fprintf(stderr,"Dice plan (%s) already exists cmpflag.%d\n",planstr,cmpflag); + return(0); + } + return(cp); +} + UniValue DiceInfo(uint256 diceid) { - UniValue result(UniValue::VOBJ); uint256 hashBlock; CTransaction vintx; int64_t minbet,maxbet,maxodds,forfeitblocks; uint64_t sbits; char str[67],numstr[65]; + 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; if ( GetTransaction(diceid,vintx,hashBlock,false) == 0 ) { fprintf(stderr,"cant find fundingtxid\n"); result.push_back(Pair("error","cant find fundingtxid")); return(result); } - if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) == 0 ) + if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) == 0 ) { fprintf(stderr,"fundingtxid isnt dice creation txid\n"); result.push_back(Pair("error","fundingtxid isnt dice creation txid")); @@ -337,15 +769,18 @@ UniValue DiceInfo(uint256 diceid) sprintf(numstr,"%.8f",(double)maxbet/COIN); result.push_back(Pair("maxbet",numstr)); result.push_back(Pair("maxodds",maxodds)); - result.push_back(Pair("forfeitblocks",forfeitblocks)); - sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN); + result.push_back(Pair("timeoutblocks",timeoutblocks)); + cp = CCinit(&C,EVAL_DICE); + dicepk = GetUnspendable(cp,0); + funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,diceid); + sprintf(numstr,"%.8f",(double)funding/COIN); result.push_back(Pair("funding",numstr)); return(result); } UniValue DiceList() { - UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits; int64_t minbet,maxbet,maxodds,forfeitblocks; char str[65]; + UniValue result(UniValue::VARR); std::vector > addressIndex; struct CCcontract_info *cp,C; uint256 txid,hashBlock; CTransaction vintx; uint64_t sbits; int64_t minbet,maxbet,maxodds,timeoutblocks; char str[65]; cp = CCinit(&C,EVAL_DICE); SetCCtxids(addressIndex,cp->normaladdr); for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) @@ -353,7 +788,7 @@ UniValue DiceList() txid = it->first.txhash; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,forfeitblocks) != 0 ) + if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 0 ) { result.push_back(uint256_str(str,txid)); } @@ -362,30 +797,23 @@ UniValue DiceList() return(result); } -std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t forfeitblocks) +std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks) { - CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C; - if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || forfeitblocks < 0 || forfeitblocks > 1440 ) + CMutableTransaction mtx; uint256 zero; CScript fundingPubKey; CPubKey mypk,dicepk; int64_t a,b,c,d; uint64_t sbits; struct CCcontract_info *cp,C; + if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 1 || timeoutblocks < 0 || timeoutblocks > 1440 ) { fprintf(stderr,"negative parameter error\n"); return(0); } - cp = CCinit(&C,EVAL_DICE); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - dicepk = GetUnspendable(cp,0); - sbits = stringbits(planstr); - if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) != 0 ) - { - fprintf(stderr,"Dice plan (%s) already exists\n",planstr); + memset(&zero,0,sizeof(zero)); + if ( (cp= Diceinit(fundingPubKey,zero,&C,planstr,txfee,mypk,dicepk,sbits,a,b,c,d)) == 0 ) return(0); - } - if ( AddNormalinputs(mtx,mypk,funds+2*txfee,64) > 0 ) + if ( AddNormalinputs(mtx,mypk,funds+3*txfee,60) > 0 ) { mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,dicepk)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(dicepk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,forfeitblocks))); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceFundingOpRet('F',sbits,minbet,maxbet,maxodds,timeoutblocks))); } fprintf(stderr,"cant find enough inputs\n"); return(0); @@ -393,120 +821,256 @@ std::string DiceCreateFunding(uint64_t txfee,char *planstr,int64_t funds,int64_t std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t amount) { - CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t a,b,c,d; struct CCcontract_info *cp,C; + 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; if ( amount < 0 ) { fprintf(stderr,"negative parameter error\n"); return(0); } - cp = CCinit(&C,EVAL_DICE); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - dicepk = GetUnspendable(cp,0); - sbits = stringbits(planstr); - if ( DicePlanExists(cp,sbits,dicepk,a,b,c,d) == 0 ) - { - fprintf(stderr,"Dice plan %s doesnt exist\n",planstr); + if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) return(0); - } - sbits = stringbits(planstr); - if ( AddNormalinputs(mtx,mypk,amount+txfee,64) > 0 ) + scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG; + if ( 0 ) { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('A',sbits,fundingtxid))); - } else fprintf(stderr,"cant find enough inputs\n"); - fprintf(stderr,"cant find fundingtxid\n"); + uint8_t *ptr0,*ptr1; int32_t i; + ptr0 = (uint8_t *)scriptPubKey.data(); + ptr1 = (uint8_t *)fundingPubKey.data(); + for (i=0; i<35; i++) + fprintf(stderr,"%02x",ptr0[i]); + fprintf(stderr," script vs "); + for (i=0; i<35; i++) + fprintf(stderr,"%02x",ptr1[i]); + fprintf(stderr," funding\n"); + } + if ( scriptPubKey == fundingPubKey ) + { + if ( AddNormalinputs(mtx,mypk,amount+2*txfee,60) > 0 ) + { + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,dicepk)); + mtx.vout.push_back(CTxOut(txfee,fundingPubKey)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('E',sbits,fundingtxid,hentropy,zeroid))); + } else fprintf(stderr,"cant find enough inputs\n"); + } else fprintf(stderr,"only fund creator can add more funds (entropy)\n"); return(0); } std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds) { - CMutableTransaction mtx; CPubKey mypk,dicepk; CScript opret; uint64_t sbits; int64_t funding,minbet,maxbet,maxodds,forfeitblocks; struct CCcontract_info *cp,C; + 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; if ( bet < 0 || odds < 1 ) { fprintf(stderr,"negative parameter error\n"); return(0); } - cp = CCinit(&C,EVAL_DICE); - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - dicepk = GetUnspendable(cp,0); - sbits = stringbits(planstr); - if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 ) + if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) + return(0); + if ( bet < minbet || bet > maxbet || odds > maxodds ) { - fprintf(stderr,"Dice plan %s doesnt exist\n",planstr); + 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); return(0); } - if ( bet < minbet ) + if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid)) >= 2*bet*odds+txfee && entropyval != 0 ) { - fprintf(stderr,"Dice plan %s bet %.8f < minbet %.8f\n",planstr,(double)bet/COIN,(double)minbet/COIN); - return(0); - } - if ( (funding= DicePlanFunds(sbits,cp,dicepk,fundingtxid)) >= bet*odds+txfee ) - { - if ( AddNormalinputs(mtx,mypk,bet+2*txfee,64) > 0 ) + if ( myIsutxo_spentinmempool(entropytxid,0) != 0 ) { + fprintf(stderr,"entropy txid is spent\n"); + return(0); + } + mtx.vin.push_back(CTxIn(entropytxid,0,CScript())); + if ( AddNormalinputs(mtx,mypk,bet+2*txfee+odds,60) > 0 ) + { + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk)); mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk)); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('L',sbits,fundingtxid))); + mtx.vout.push_back(CTxOut(txfee+odds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeDiceOpRet('B',sbits,fundingtxid,entropy,zeroid))); } else fprintf(stderr,"cant find enough inputs %.8f note enough for %.8f\n",(double)funding/COIN,(double)bet/COIN); } - fprintf(stderr,"cant find dice inputs\n"); + if ( entropyval == 0 && funding != 0 ) + fprintf(stderr,"cant find dice entropy inputs\n"); + else fprintf(stderr,"cant find dice inputs\n"); return(0); } -std::string DiceUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 locktxid) +std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout) { - CMutableTransaction mtx; CTransaction tx; char coinaddr[64]; CPubKey mypk,dicepk; CScript opret,scriptPubKey,ignore; uint256 hashBlock; uint64_t funding,sbits,reward=0,amount=0,inputs,CCchange=0; int64_t minbet,maxbet,maxodds,forfeitblocks; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_DICE); - if ( txfee == 0 ) - txfee = 10000; - dicepk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - sbits = stringbits(planstr); - if ( DicePlanExists(cp,sbits,dicepk,minbet,maxbet,maxodds,forfeitblocks) == 0 ) + CMutableTransaction mtx; CScript scriptPubKey,fundingPubKey; CTransaction betTx,entropyTx; uint256 hentropyproof,entropytxid,hashBlock,bettorentropy,entropy,hentropy; CPubKey mypk,dicepk,fundingpk; 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; + *resultp = 0; + //char str[65]; fprintf(stderr,"DiceBetFinish.%s %s\n",planstr,uint256_str(str,bettxid)); + if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) { - fprintf(stderr,"Dice plan %s doesnt exist\n",planstr); - return(0); + fprintf(stderr,"Diceinit error\n"); + return("0"); } - // need to deal with finding the right utxos - if ( locktxid == zeroid ) - amount = AddDiceInputs(scriptPubKey,0,cp,mtx,dicepk,(1LL << 30),1); - else + fundingpk = DiceFundingPk(fundingPubKey); + if ( winlosetimeout != 0 ) { - GetCCaddress(cp,coinaddr,dicepk); - if ( (amount= CCutxovalue(coinaddr,locktxid,0)) == 0 ) + scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG; + if ( scriptPubKey != fundingPubKey ) { - fprintf(stderr,"%s locktxid/v0 is spent\n",coinaddr); - return(0); + fprintf(stderr,"only dice fund creator can submit winner or loser\n"); + return("0"); } - if ( GetTransaction(locktxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) + } + if ( AddNormalinputs(mtx,mypk,txfee,1) == 0 ) + { + fprintf(stderr,"no txfee inputs for win/lose\n"); + return("0"); + } + if ( GetTransaction(bettxid,betTx,hashBlock,false) != 0 && GetTransaction(betTx.vin[0].prevout.hash,entropyTx,hashBlock,false) != 0 ) + { + bettorentropy = DiceGetEntropy(betTx,'B'); + if ( winlosetimeout == 0 || (iswin= DiceIsWinner(hentropyproof,bettxid,betTx,entropyTx,bettorentropy,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 ) { - scriptPubKey = tx.vout[1].scriptPubKey; - mtx.vin.push_back(CTxIn(locktxid,0,CScript())); + winlosetimeout = iswin; + if ( iswin == winlosetimeout ) + { + if ( myIsutxo_spentinmempool(bettxid,0) != 0 || myIsutxo_spentinmempool(bettxid,1) != 0 ) + { + fprintf(stderr,"bettxid already spent\n"); + return("0"); + } + //fprintf(stderr,"iswin.%d matches\n",iswin); + mtx.vin.push_back(CTxIn(bettxid,0,CScript())); + mtx.vin.push_back(CTxIn(bettxid,1,CScript())); + if ( iswin == 0 ) + { + funcid = 'T'; + if ( DiceVerifyTimeout(betTx,timeoutblocks) == 0 ) // hasnt timed out yet + { + fprintf(stderr,"timeout is not supported yet\n"); + return("0"); + } + else + { + hentropy = hentropyproof = zeroid; + iswin = 1; + } + } + if ( iswin > 0 ) + { + funcid = 'W'; + odds = (betTx.vout[2].nValue - txfee); + if ( odds < 1 || odds > maxodds ) + { + fprintf(stderr,"illegal odds.%d vs maxodds.%d\n",(int32_t)odds,(int32_t)maxodds); + return("0"); + } + CCchange = betTx.vout[0].nValue; + fundsneeded = txfee + odds*betTx.vout[1].nValue; + if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60)) > 0 ) + { + if ( inputs > fundsneeded ) + CCchange += (inputs - fundsneeded); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk)); + mtx.vout.push_back(CTxOut(txfee,fundingPubKey)); + mtx.vout.push_back(CTxOut((odds+1) * betTx.vout[1].nValue,betTx.vout[2].scriptPubKey)); + } + else + { + fprintf(stderr,"not enough inputs for %.8f\n",(double)fundsneeded/COIN); + return("0"); + } + } + else + { + funcid = 'L'; + mtx.vout.push_back(MakeCC1vout(cp->evalcode,betTx.vout[0].nValue + betTx.vout[1].nValue,dicepk)); + mtx.vout.push_back(CTxOut(txfee,fundingPubKey)); + } + if ( winlosetimeout != 0 ) + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); + *resultp = 1; + //char str[65],str2[65]; + //fprintf(stderr,"iswin.%d house entropy %s vs bettor %s\n",iswin,uint256_str(str,hentropyproof),uint256_str(str2,bettorentropy)); + return(FinalizeCCTx(0,cp,mtx,fundingpk,txfee,EncodeDiceOpRet(funcid,sbits,fundingtxid,hentropy,hentropyproof))); + } else fprintf(stderr,"iswin.%d does not match.%d\n",iswin,winlosetimeout); } else { - fprintf(stderr,"%s no normal vout.1 in locktxid\n",coinaddr); - return(0); + *resultp = -1; + fprintf(stderr,"iswin.%d winlosetimeout.%d\n",iswin,winlosetimeout); + return("0"); } } - if ( amount > 0 && (reward= DiceCalc(amount,mtx.vin[0].prevout.hash,minbet,maxbet,maxodds,forfeitblocks)) > txfee && scriptPubKey.size() > 0 ) - { - if ( (inputs= AddDiceInputs(ignore,1,cp,mtx,dicepk,reward+txfee,30)) > 0 ) - { - if ( inputs >= (reward + 2*txfee) ) - CCchange = (inputs - (reward + txfee)); - fprintf(stderr,"inputs %.8f CCchange %.8f amount %.8f reward %.8f\n",(double)inputs/COIN,(double)CCchange/COIN,(double)amount/COIN,(double)reward/COIN); - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange,dicepk)); - mtx.vout.push_back(CTxOut(amount+reward,scriptPubKey)); - return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,EncodeDiceOpRet('U',sbits,fundingtxid))); - } - fprintf(stderr,"cant find enough dice inputs\n"); - } - fprintf(stderr,"amount %.8f -> reward %.8f\n",(double)amount/COIN,(double)reward/COIN); - return(0); + *resultp = -1; + fprintf(stderr,"couldnt find bettx or entropytx\n"); + return("0"); } +double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid) +{ + CScript fundingPubKey,scriptPubKey; CTransaction spenttx,betTx; uint256 hash,proof,txid,hashBlock,spenttxid; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int32_t i,result,vout,n=0; int64_t minbet,maxbet,maxodds,timeoutblocks; uint64_t sbits; char coinaddr[64]; std::string res; + if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) + { + fprintf(stderr,"Diceinit error\n"); + return(0.); + } + fundingpk = DiceFundingPk(fundingPubKey); + scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG; + GetCCaddress(cp,coinaddr,dicepk); + if ( bettxid == zeroid ) // scan + { + std::vector > unspentOutputs; + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + if ( GetTransaction(txid,betTx,hashBlock,false) != 0 && betTx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + { + if ( DecodeDiceOpRet(txid,betTx.vout[betTx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof) == 'B' ) + { + res = DiceBetFinish(&result,txfee,planstr,fundingtxid,txid,scriptPubKey == fundingPubKey); + if ( result > 0 ) + { + mySendrawtransaction(res); + n++; + } + } + } + } + if ( scriptPubKey == fundingPubKey ) + { + for (i=0; i<=n; i++) + { + res = DiceAddfunding(txfee,planstr,fundingtxid,COIN); + fprintf(stderr,"ENTROPY tx:\n"); + mySendrawtransaction(res); + } + } + return(n); + } + else + { + if ( (vout= myIsutxo_spent(spenttxid,bettxid,1)) >= 0 ) + { + if ( GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() > 2 ) + { + if ( spenttx.vout[2].scriptPubKey == fundingPubKey ) + return(0.); + else return((double)spenttx.vout[2].nValue/COIN); + } else return(0.); + } + else if ( scriptPubKey == fundingPubKey ) + res = DiceBetFinish(&result,txfee,planstr,fundingtxid,bettxid,1); + else res = DiceBetFinish(&result,txfee,planstr,fundingtxid,bettxid,0); + if ( result > 0 ) + { + mySendrawtransaction(res); + sleep(1); + if ( (vout= myIsutxo_spent(spenttxid,bettxid,1)) >= 0 ) + { + if ( GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() >= 2 ) + { + if ( spenttx.vout[2].scriptPubKey == fundingPubKey || ((uint8_t *)spenttx.vout[2].scriptPubKey.data())[0] == 0x6a ) + return(0.); + else return((double)spenttx.vout[2].nValue/COIN); + } else return(0.); + } + fprintf(stderr,"didnt find dicefinish tx\n"); + } else return(-1.); + } + return(0.); +} diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index f157b6197..95f5c33de 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -30,12 +30,15 @@ Eval* EVAL_TEST = 0; struct CCcontract_info CCinfos[0x100]; +extern pthread_mutex_t KOMODO_CC_mutex; bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn) { EvalRef eval; + pthread_mutex_lock(&KOMODO_CC_mutex); bool out = eval->Dispatch(cond, tx, nIn); - //fprintf(stderr,"out %d vs %d isValid\n",(int32_t)out,(int32_t)eval->state.IsValid()); + pthread_mutex_unlock(&KOMODO_CC_mutex); + //fprintf(stderr,"out %d vs %d isValid\n",(int32_t)out,(int32_t)eval->state.IsValid()); assert(eval->state.IsValid() == out); if (eval->state.IsValid()) return true; @@ -95,7 +98,6 @@ bool Eval::GetSpendsConfirmed(uint256 hash, std::vector &spends) c bool Eval::GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const { - bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock); // there is a LOCK(cs_main) in the normal GetTransaction(), which leads to deadlocks //bool fAllowSlow = false; // Don't allow slow //return GetTransaction(hash, txOut, hashBlock, fAllowSlow); diff --git a/src/cc/eval.h b/src/cc/eval.h index 9d69c5fd5..77c592a16 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -44,7 +44,7 @@ EVAL(EVAL_FAUCET, 0xe4) \ EVAL(EVAL_REWARDS, 0xe5) \ EVAL(EVAL_DICE, 0xe6) \ - EVAL(EVAL_PONZI, 0xe7) \ + EVAL(EVAL_FSM, 0xe7) \ EVAL(EVAL_AUCTION, 0xe8) \ EVAL(EVAL_LOTTO, 0xe9) diff --git a/src/cc/faucet.cpp b/src/cc/faucet.cpp index 3891a3f9e..51d7f2f6f 100644 --- a/src/cc/faucet.cpp +++ b/src/cc/faucet.cpp @@ -136,7 +136,7 @@ uint64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPu // prevent dup if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( (nValue= IsFaucetvout(cp,vintx,(int32_t)it->first.index)) > 0 ) + if ( (nValue= IsFaucetvout(cp,vintx,(int32_t)it->first.index)) > 1000000 ) { if ( total != 0 && maxinputs != 0 ) mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript())); @@ -187,4 +187,17 @@ std::string FaucetFund(uint64_t txfee,uint64_t funds) return(0); } +UniValue FaucetInfo() +{ + UniValue result(UniValue::VOBJ); char numstr[64]; + CMutableTransaction mtx; CPubKey faucetpk; struct CCcontract_info *cp,C; uint64_t funding; + result.push_back(Pair("result","success")); + result.push_back(Pair("name","Faucet")); + cp = CCinit(&C,EVAL_FAUCET); + faucetpk = GetUnspendable(cp,0); + funding = AddFaucetInputs(cp,mtx,faucetpk,0,0); + sprintf(numstr,"%.8f",(double)funding/COIN); + result.push_back(Pair("funding",numstr)); + return(result); +} diff --git a/src/cc/ponzi.cpp b/src/cc/fsm.cpp similarity index 71% rename from src/cc/ponzi.cpp rename to src/cc/fsm.cpp index c29f63ebc..201535992 100644 --- a/src/cc/ponzi.cpp +++ b/src/cc/fsm.cpp @@ -13,7 +13,7 @@ * * ******************************************************************************/ -#include "CCponzi.h" +#include "CCfsm.h" #include "../txmempool.h" /* @@ -21,7 +21,7 @@ // start of consensus code -uint64_t IsPonzivout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) +uint64_t IsFSMvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) { char destaddr[64]; if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) @@ -32,7 +32,7 @@ uint64_t IsPonzivout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v return(0); } -bool PonziExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) +bool FSMExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) { static uint256 zerohash; CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; uint64_t inputs=0,outputs=0,assetoshis; @@ -50,8 +50,8 @@ bool PonziExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction { //fprintf(stderr,"vini.%d check hash and vout\n",i); if ( hashBlock == zerohash ) - return eval->Invalid("cant ponzi from mempool"); - if ( (assetoshis= IsPonzivout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) + return eval->Invalid("cant FSM from mempool"); + if ( (assetoshis= IsFSMvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) inputs += assetoshis; } } @@ -59,7 +59,7 @@ bool PonziExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction for (i=0; iInvalid("illegal normal vini"); } } //fprintf(stderr,"check amounts\n"); - if ( PonziExactAmounts(cp,eval,tx,1,10000) == false ) + if ( FSMExactAmounts(cp,eval,tx,1,10000) == false ) { - fprintf(stderr,"ponziget invalid amount\n"); + fprintf(stderr,"fsmget invalid amount\n"); return false; } else { preventCCvouts = 1; - if ( IsPonzivout(cp,tx,0) != 0 ) + if ( IsFSMvout(cp,tx,0) != 0 ) { preventCCvouts++; i = 1; } else i = 0; if ( tx.vout[i].nValue != COIN ) - return eval->Invalid("invalid ponzi output"); + return eval->Invalid("invalid fsm output"); retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) - fprintf(stderr,"ponziget validated\n"); - else fprintf(stderr,"ponziget invalid\n"); + fprintf(stderr,"fsmget validated\n"); + else fprintf(stderr,"fsmget invalid\n"); return(retval); } } @@ -117,7 +117,7 @@ bool PonziValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) // helper functions for rpc calls in rpcwallet.cpp -uint64_t AddPonziInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs) +uint64_t AddFSMInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs) { char coinaddr[64]; uint64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t n = 0; std::vector > unspentOutputs; @@ -127,9 +127,11 @@ uint64_t AddPonziInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub { txid = it->first.txhash; // prevent dup + if ( it->second.satoshis < 1000000 ) + continue; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( (nValue= IsPonzivout(cp,vintx,(int32_t)it->first.index)) > 0 ) + if ( (nValue= IsFSMvout(cp,vintx,(int32_t)it->first.index)) > 0 ) { if ( total != 0 && maxinputs != 0 ) mtx.vin.push_back(CTxIn(txid,(int32_t)it->first.index,CScript())); @@ -144,39 +146,37 @@ uint64_t AddPonziInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub return(totalinputs); } -std::string PonziBuy(uint64_t txfee,uint64_t amount) +std::string FSMList() { - CMutableTransaction mtx; CPubKey mypk,ponzipk; CScript opret; uint64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_PONZI); + return(0); +} + +std::string FSMCreate(uint64_t txfee,std::string name,std::string states) +{ + CMutableTransaction mtx; CPubKey mypk,fsmpk; CScript opret; uint64_t inputs,CCchange=0,nValue=COIN; struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_FSM); if ( txfee == 0 ) txfee = 10000; - ponzipk = GetUnspendable(cp,0); + fsmpk = GetUnspendable(cp,0); mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddPonziInputs(cp,mtx,ponzipk,nValue+txfee,60)) > 0 ) + if ( (inputs= AddFSMInputs(cp,mtx,fsmpk,nValue+txfee,60)) > 0 ) { if ( inputs > nValue ) CCchange = (inputs - nValue - txfee); if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_PONZI,CCchange,ponzipk)); + mtx.vout.push_back(MakeCC1vout(EVAL_FSM,CCchange,fsmpk)); mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); return(FinalizeCCTx(-1LL,cp,mtx,mypk,txfee,opret)); - } else fprintf(stderr,"cant find ponzi inputs\n"); + } else fprintf(stderr,"cant find fsm inputs\n"); return(0); } -std::string PonziClaim(uint64_t txfee) +std::string FSMInfo(uint256 fsmtxid) { - CMutableTransaction mtx; CPubKey mypk,ponzipk; uint64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_PONZI); - if ( txfee == 0 ) - txfee = 10000; + CMutableTransaction mtx; CPubKey mypk,fsmpk; uint64_t funds = 0; CScript opret; struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_FSM); mypk = pubkey2pk(Mypubkey()); - ponzipk = GetUnspendable(cp,0); - if ( AddNormalinputs(mtx,mypk,txfee,64) > 0 ) - { - mtx.vout.push_back(MakeCC1vout(EVAL_PONZI,funds,ponzipk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); - } + fsmpk = GetUnspendable(cp,0); return(0); } diff --git a/src/cc/lotto.cpp b/src/cc/lotto.cpp index f15650f5e..43367ab70 100644 --- a/src/cc/lotto.cpp +++ b/src/cc/lotto.cpp @@ -127,6 +127,8 @@ uint64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub { txid = it->first.txhash; // prevent dup + if ( it->second.satoshis < 1000000 ) + continue; if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { if ( (nValue= IsLottovout(cp,vintx,(int32_t)it->first.index)) > 0 ) diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index ba7cd5657..c2f6dcd27 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -72,6 +72,7 @@ uint64_t RewardsCalc(uint64_t amount,uint256 txid,uint64_t APR,uint64_t minsecon fprintf(stderr,"minseconds %llu maxseconds %llu\n",(long long)minseconds,(long long)maxseconds); if ( (duration= CCduration(txid)) < minseconds ) { + fprintf(stderr,"duration %llu < minseconds %llu\n",(long long)duration,(long long)minseconds); return(0); //duration = (uint32_t)time(NULL) - (1532713903 - 3600 * 24); } else if ( duration > maxseconds ) @@ -273,6 +274,8 @@ uint64_t AddRewardsInputs(CScript &scriptPubKey,int32_t fundsflag,struct CCcontr { txid = it->first.txhash; vout = (int32_t)it->first.index; + if ( it->second.satoshis < 1000000 ) + continue; fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); for (j=0; j= 0 ) return(height2); } - if ( block->vtx[0].vin.size() > 0 ) + if ( block != 0 && block->vtx[0].vin.size() > 0 ) { #ifdef KOMODO_ZCASH ptr = (uint8_t *)block->vtx[0].vin[0].scriptSig.data(); diff --git a/src/main.cpp b/src/main.cpp index 79182bad8..b42f85ce7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1603,6 +1603,26 @@ bool GetAddressUnspent(uint160 addressHash, int type, return true; } +/*uint64_t myGettxout(uint256 hash,int32_t n) +{ + CCoins coins; + LOCK2(cs_main,mempool.cs); + CCoinsViewMemPool view(pcoinsTip, mempool); + if (!view.GetCoins(hash, coins)) + return(0); + if ( n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull() ) + return(0); + else return(coins.vout[n].nValue); +}*/ + +bool myAddtomempool(CTransaction &tx) +{ + CValidationState state; CTransaction Ltx; bool fMissingInputs,fOverrideFees = false; + if ( mempool.lookup(tx.GetHash(),Ltx) == 0 ) + return(AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)); + else return(true); +} + bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) { // need a GetTransaction without lock so the validation code for assets can run without deadlock diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 2e5ed0be8..b76698917 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -346,6 +346,25 @@ UniValue getdifficulty(const UniValue& params, bool fHelp) return GetNetworkDifficulty(); } +bool myIsutxo_spentinmempool(uint256 txid,int32_t vout) +{ + //char *uint256_str(char *str,uint256); char str[65]; + LOCK(mempool.cs); + BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) + { + const CTransaction &tx = e.GetTx(); + const uint256 &hash = tx.GetHash(); + BOOST_FOREACH(const CTxIn &txin,tx.vin) + { + //fprintf(stderr,"%s/v%d ",uint256_str(str,txin.prevout.hash),txin.prevout.n); + if ( txin.prevout.n == vout && txin.prevout.hash == txid ) + return(true); + } + //fprintf(stderr,"are vins for %s\n",uint256_str(str,hash)); + } + return(false); +} + UniValue mempoolToJSON(bool fVerbose = false) { if (fVerbose) diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp index 125be1d73..798b991d7 100644 --- a/src/rpcrawtransaction.cpp +++ b/src/rpcrawtransaction.cpp @@ -119,6 +119,19 @@ UniValue TxJoinSplitToJSON(const CTransaction& tx) { uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); +int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout) +{ + CSpentIndexValue spentInfo; CSpentIndexKey spentKey(txid,vout); + if ( GetSpentIndex(spentKey,spentInfo) ) + { + spenttxid = spentInfo.txid; + return((int32_t)spentInfo.inputIndex); + // out.push_back(Pair("spentHeight", spentInfo.blockHeight)); + } + memset(&spenttxid,0,sizeof(spenttxid)); + return(-1); +} + void TxToJSONExpanded(const CTransaction& tx, const uint256 hashBlock, UniValue& entry, int nHeight = 0, int nConfirmations = 0, int nBlockTime = 0) { uint256 txid = tx.GetHash(); @@ -267,6 +280,8 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry) vout.push_back(out); } entry.push_back(Pair("vout", vout)); + UniValue vjoinsplit = TxJoinSplitToJSON(tx); + entry.push_back(Pair("vjoinsplit", vjoinsplit)); if (!hashBlock.IsNull()) { entry.push_back(Pair("blockhash", hashBlock.GetHex())); @@ -1137,7 +1152,7 @@ UniValue sendrawtransaction(const UniValue& params, bool fHelp) } } else if (fHaveChain) { throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); - } + } RelayTransaction(tx); return hashTx.GetHex(); diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 580a050c3..06fdc433b 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -350,8 +350,11 @@ static const CRPCCommand vRPCCommands[] = /* lotto */ { "lotto", "lottoaddress", &lottoaddress, true }, - /* ponzi */ - { "ponzi", "ponziaddress", &ponziaddress, true }, + /* fsm */ + { "FSM", "FSMaddress", &FSMaddress, true }, + { "FSMcreate", "FSMcreate", &FSMcreate, true }, + { "FSMlist", "FSMlist", &FSMlist, true }, + { "FSMinfo", "FSMinfo", &FSMinfo, true }, /* rewards */ { "rewards", "rewardslist", &rewardslist, true }, @@ -363,6 +366,7 @@ static const CRPCCommand vRPCCommands[] = { "rewards", "rewardsaddress", &rewardsaddress, true }, /* faucet */ + { "faucet", "faucetinfo", &faucetinfo, true }, { "faucet", "faucetfund", &faucetfund, true }, { "faucet", "faucetget", &faucetget, true }, { "faucet", "faucetaddress", &faucetaddress, true }, @@ -373,6 +377,8 @@ static const CRPCCommand vRPCCommands[] = { "dice", "dicefund", &dicefund, true }, { "dice", "diceaddfunds", &diceaddfunds, true }, { "dice", "dicebet", &dicebet, true }, + { "dice", "dicefinish", &dicefinish, true }, + { "dice", "dicestatus", &dicestatus, true }, { "dice", "diceaddress", &diceaddress, true }, /* tokens */ diff --git a/src/rpcserver.h b/src/rpcserver.h index 4da7c73c0..4b5dcdc2c 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -226,6 +226,7 @@ extern UniValue tokenfillswap(const UniValue& params, bool fHelp); extern UniValue faucetfund(const UniValue& params, bool fHelp); extern UniValue faucetget(const UniValue& params, bool fHelp); extern UniValue faucetaddress(const UniValue& params, bool fHelp); +extern UniValue faucetinfo(const UniValue& params, bool fHelp); extern UniValue rewardsinfo(const UniValue& params, bool fHelp); extern UniValue rewardslist(const UniValue& params, bool fHelp); extern UniValue rewardsaddress(const UniValue& params, bool fHelp); @@ -239,8 +240,13 @@ extern UniValue dicelist(const UniValue& params, bool fHelp); extern UniValue diceinfo(const UniValue& params, bool fHelp); extern UniValue diceaddfunds(const UniValue& params, bool fHelp); extern UniValue dicebet(const UniValue& params, bool fHelp); +extern UniValue dicefinish(const UniValue& params, bool fHelp); +extern UniValue dicestatus(const UniValue& params, bool fHelp); extern UniValue lottoaddress(const UniValue& params, bool fHelp); -extern UniValue ponziaddress(const UniValue& params, bool fHelp); +extern UniValue FSMaddress(const UniValue& params, bool fHelp); +extern UniValue FSMcreate(const UniValue& params, bool fHelp); +extern UniValue FSMlist(const UniValue& params, bool fHelp); +extern UniValue FSMinfo(const UniValue& params, bool fHelp); extern UniValue auctionaddress(const UniValue& params, bool fHelp); extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0bc73e9f1..295460618 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4844,18 +4844,18 @@ int32_t ensure_CCrequirements() #include "../cc/CCassets.h" #include "../cc/CCrewards.h" #include "../cc/CCdice.h" -#include "../cc/CCponzi.h" +#include "../cc/CCfsm.h" #include "../cc/CCauction.h" #include "../cc/CClotto.h" UniValue CCaddress(struct CCcontract_info *cp,char *name,std::vector &pubkey) { - UniValue result(UniValue::VOBJ); ; char destaddr[64],str[64],marker[64]; + UniValue result(UniValue::VOBJ); ; char destaddr[64],str[64]; result.push_back(Pair("result", "success")); sprintf(str,"%sCCaddress",name); - sprintf(marker,"%smarker",name); - if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 ) - result.push_back(Pair(str,destaddr)); + result.push_back(Pair(str,cp->unspendableCCaddr)); + sprintf(str,"%smarker",name); + result.push_back(Pair(str,cp->normaladdr)); if ( pubkey.size() == 33 ) { if ( GetCCaddress(cp,destaddr,pubkey2pk(pubkey)) != 0 ) @@ -4881,17 +4881,17 @@ UniValue lottoaddress(const UniValue& params, bool fHelp) return(CCaddress(cp,(char *)"Lotto",pubkey)); } -UniValue ponziaddress(const UniValue& params, bool fHelp) +UniValue FSMaddress(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; std::vector pubkey; - cp = CCinit(&C,EVAL_PONZI); + cp = CCinit(&C,EVAL_FSM); if ( fHelp || params.size() > 1 ) - throw runtime_error("ponziaddress [pubkey]\n"); + throw runtime_error("FSMaddress [pubkey]\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); if ( params.size() == 1 ) pubkey = ParseHex(params[0].get_str().c_str()); - return(CCaddress(cp,(char *)"Ponzi",pubkey)); + return(CCaddress(cp,(char *)"FSM",pubkey)); } UniValue auctionaddress(const UniValue& params, bool fHelp) @@ -4966,7 +4966,9 @@ UniValue rewardscreatefunding(const UniValue& params, bool fHelp) throw runtime_error("rewardscreatefunding name amount APR mindays maxdays mindeposit\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); - // default to OOT params + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + // default to OOT params APR = 5 * COIN; minseconds = maxseconds = 60 * 3600 * 24; mindeposit = 100 * COIN; @@ -5002,6 +5004,8 @@ UniValue rewardslock(const UniValue& params, bool fHelp) throw runtime_error("rewardslock name fundingtxid amount\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; @@ -5021,6 +5025,8 @@ UniValue rewardsaddfunding(const UniValue& params, bool fHelp) throw runtime_error("rewardsaddfunding name fundingtxid amount\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; @@ -5040,6 +5046,8 @@ UniValue rewardsunlock(const UniValue& params, bool fHelp) throw runtime_error("rewardsunlock name fundingtxid [txid]\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); if ( params.size() > 2 ) @@ -5075,6 +5083,57 @@ UniValue rewardsinfo(const UniValue& params, bool fHelp) return(RewardsInfo(fundingtxid)); } +UniValue FSMcreate(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); std::string name,states,hex; + if ( fHelp || params.size() != 2 ) + throw runtime_error("FSMcreate name states\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + name = params[0].get_str(); + states = params[1].get_str(); + hex = FSMCreate(0,name,states); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else result.push_back(Pair("error", "couldnt create FSM transaction")); + return(result); +} + +UniValue FSMlist(const UniValue& params, bool fHelp) +{ + uint256 tokenid; + if ( fHelp || params.size() > 0 ) + throw runtime_error("FSMlist\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + return(FSMList()); +} + +UniValue FSMinfo(const UniValue& params, bool fHelp) +{ + uint256 FSMtxid; + if ( fHelp || params.size() != 1 ) + throw runtime_error("FSMinfo fundingtxid\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + FSMtxid = Parseuint256((char *)params[0].get_str().c_str()); + return(FSMInfo(FSMtxid)); +} + +UniValue faucetinfo(const UniValue& params, bool fHelp) +{ + uint256 fundingtxid; + if ( fHelp || params.size() != 0 ) + throw runtime_error("faucetinfo\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + return(FaucetInfo()); +} + UniValue faucetfund(const UniValue& params, bool fHelp) { UniValue result(UniValue::VOBJ); uint64_t funds; std::string hex; @@ -5082,6 +5141,8 @@ UniValue faucetfund(const UniValue& params, bool fHelp) throw runtime_error("faucetfund amount\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); funds = atof(params[0].get_str().c_str()) * COIN; hex = FaucetFund(0,funds); if ( hex.size() > 0 ) @@ -5099,6 +5160,8 @@ UniValue faucetget(const UniValue& params, bool fHelp) throw runtime_error("faucetget\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); hex = FaucetGet(0); if ( hex.size() > 0 ) { @@ -5110,18 +5173,20 @@ UniValue faucetget(const UniValue& params, bool fHelp) UniValue dicefund(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,forfeitblocks; std::string hex; char *name; + UniValue result(UniValue::VOBJ); int64_t funds,minbet,maxbet,maxodds,timeoutblocks; std::string hex; char *name; if ( fHelp || params.size() != 6 ) - throw runtime_error("dicefund name funds minbet maxbet maxodds forfeitblocks\n"); + throw runtime_error("dicefund name funds minbet maxbet maxodds timeoutblocks\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); funds = atof(params[1].get_str().c_str()) * COIN; minbet = atof(params[2].get_str().c_str()) * COIN; maxbet = atof(params[3].get_str().c_str()) * COIN; maxodds = atol(params[4].get_str().c_str()); - forfeitblocks = atol(params[5].get_str().c_str()); - hex = DiceCreateFunding(0,name,funds,minbet,maxbet,maxodds,forfeitblocks); + timeoutblocks = atol(params[5].get_str().c_str()); + hex = DiceCreateFunding(0,name,funds,minbet,maxbet,maxodds,timeoutblocks); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); @@ -5137,6 +5202,8 @@ UniValue diceaddfunds(const UniValue& params, bool fHelp) throw runtime_error("diceaddfunds name fundingtxid amount\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; @@ -5156,6 +5223,8 @@ UniValue dicebet(const UniValue& params, bool fHelp) throw runtime_error("dicebet name fundingtxid amount odds\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); name = (char *)params[0].get_str().c_str(); fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); amount = atof(params[2].get_str().c_str()) * COIN; @@ -5169,6 +5238,68 @@ UniValue dicebet(const UniValue& params, bool fHelp) return(result); } +UniValue dicefinish(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; uint64_t amount; std::string hex; int32_t r; + if ( fHelp || params.size() != 3 ) + throw runtime_error("dicefinish name fundingtxid bettxid\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + name = (char *)params[0].get_str().c_str(); + fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); + bettxid = Parseuint256((char *)params[2].get_str().c_str()); + hex = DiceBetFinish(&r,0,name,fundingtxid,bettxid,1); + if ( hex.size() > 0 ) + { + result.push_back(Pair("result", "success")); + result.push_back(Pair("hex", hex)); + } else result.push_back(Pair("error", "couldnt create dicefinish transaction")); + return(result); +} + +UniValue dicestatus(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; uint64_t amount; std::string status; double winnings; + if ( fHelp || (params.size() != 2 && params.size() != 3) ) + throw runtime_error("dicestatus name fundingtxid bettxid\n"); + if ( ensure_CCrequirements() < 0 ) + throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); + name = (char *)params[0].get_str().c_str(); + fundingtxid = Parseuint256((char *)params[1].get_str().c_str()); + memset(&bettxid,0,sizeof(bettxid)); + if ( params.size() == 3 ) + bettxid = Parseuint256((char *)params[2].get_str().c_str()); + winnings = DiceStatus(0,name,fundingtxid,bettxid); + result.push_back(Pair("result", "success")); + if ( winnings >= 0. ) + { + if ( winnings > 0. ) + { + if ( params.size() == 3 ) + { + result.push_back(Pair("status", "win")); + result.push_back(Pair("won", winnings)); + } + else + { + result.push_back(Pair("status", "finalized")); + result.push_back(Pair("n", (int64_t)winnings)); + } + } + else + { + if ( params.size() == 3 ) + result.push_back(Pair("status", "loss")); + else result.push_back(Pair("status", "no pending bets")); + } + } else result.push_back(Pair("status", "invalid bet txid")); + return(result); +} + UniValue dicelist(const UniValue& params, bool fHelp) { uint256 tokenid; @@ -5232,6 +5363,7 @@ UniValue tokenbalance(const UniValue& params, bool fHelp) throw runtime_error("tokenbalance tokenid [pubkey]\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + LOCK(cs_main); tokenid = Parseuint256((char *)params[0].get_str().c_str()); if ( params.size() == 2 ) pubkey = ParseHex(params[1].get_str().c_str()); @@ -5252,6 +5384,8 @@ UniValue tokencreate(const UniValue& params, bool fHelp) throw runtime_error("tokencreate name supply description\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); name = params[0].get_str(); supply = atof(params[1].get_str().c_str()) * COIN; if ( params.size() == 3 ) @@ -5272,6 +5406,8 @@ UniValue tokentransfer(const UniValue& params, bool fHelp) throw runtime_error("tokentransfer tokenid destpubkey amount\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); tokenid = Parseuint256((char *)params[0].get_str().c_str()); std::vector pubkey(ParseHex(params[1].get_str().c_str())); amount = atol(params[2].get_str().c_str()); @@ -5291,6 +5427,8 @@ UniValue tokenbid(const UniValue& params, bool fHelp) throw runtime_error("tokenbid numtokens tokenid price\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); numtokens = atoi(params[0].get_str().c_str()); tokenid = Parseuint256((char *)params[1].get_str().c_str()); price = atof(params[2].get_str().c_str()); @@ -5311,6 +5449,8 @@ UniValue tokencancelbid(const UniValue& params, bool fHelp) throw runtime_error("tokencancelbid tokenid bidtxid\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); tokenid = Parseuint256((char *)params[0].get_str().c_str()); bidtxid = Parseuint256((char *)params[1].get_str().c_str()); hex = CancelBuyOffer(0,tokenid,bidtxid); @@ -5329,6 +5469,8 @@ UniValue tokenfillbid(const UniValue& params, bool fHelp) throw runtime_error("tokenfillbid tokenid bidtxid fillamount\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); tokenid = Parseuint256((char *)params[0].get_str().c_str()); bidtxid = Parseuint256((char *)params[1].get_str().c_str()); fillamount = atol(params[2].get_str().c_str()); @@ -5348,6 +5490,8 @@ UniValue tokenask(const UniValue& params, bool fHelp) throw runtime_error("tokenask numtokens tokenid price\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); numtokens = atoi(params[0].get_str().c_str()); tokenid = Parseuint256((char *)params[1].get_str().c_str()); price = atof(params[2].get_str().c_str()); @@ -5369,6 +5513,8 @@ UniValue tokenswapask(const UniValue& params, bool fHelp) throw runtime_error("tokenswapask numtokens tokenid otherid price\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); numtokens = atoi(params[0].get_str().c_str()); tokenid = Parseuint256((char *)params[1].get_str().c_str()); otherid = Parseuint256((char *)params[2].get_str().c_str()); @@ -5390,6 +5536,8 @@ UniValue tokencancelask(const UniValue& params, bool fHelp) throw runtime_error("tokencancelask tokenid asktxid\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); tokenid = Parseuint256((char *)params[0].get_str().c_str()); asktxid = Parseuint256((char *)params[1].get_str().c_str()); hex = CancelSell(0,tokenid,asktxid); @@ -5409,6 +5557,8 @@ UniValue tokenfillask(const UniValue& params, bool fHelp) throw runtime_error("tokenfillask tokenid asktxid fillunits\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); tokenid = Parseuint256((char *)params[0].get_str().c_str()); asktxid = Parseuint256((char *)params[1].get_str().c_str()); fillunits = atol(params[2].get_str().c_str()); @@ -5429,6 +5579,8 @@ UniValue tokenfillswap(const UniValue& params, bool fHelp) throw runtime_error("tokenfillswap tokenid otherid asktxid fillunits\n"); if ( ensure_CCrequirements() < 0 ) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); + const CKeyStore& keystore = *pwalletMain; + LOCK2(cs_main, pwalletMain->cs_wallet); tokenid = Parseuint256((char *)params[0].get_str().c_str()); otherid = Parseuint256((char *)params[1].get_str().c_str()); asktxid = Parseuint256((char *)params[2].get_str().c_str()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 5100a2470..70375e663 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2117,7 +2117,7 @@ std::vector CWallet::ResendWalletTransactionsBefore(int64_t nTime) // Don't rebroadcast if newer than nTime: if (wtx.nTimeReceived > nTime) continue; - //if ( ASSETCHAINS_SYMBOL[0] == 0 ) + if ( ASSETCHAINS_SYMBOL[0] == 0 ) { if ( wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME ) {