diff --git a/src/Makefile.am b/src/Makefile.am index f18c192e2..2bd18df4d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -268,7 +268,7 @@ libbitcoin_server_a_SOURCES = \ cc/dice.cpp \ cc/lotto.cpp \ cc/fsm.cpp \ - cc/MofN.cpp \ + cc/heir.cpp \ cc/oracles.cpp \ cc/prices.cpp \ cc/pegs.cpp \ diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index 36fea57bf..f05b522fa 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -62,7 +62,7 @@ void WaitForShutdown(boost::thread_group* threadGroup) } else { - komodo_interestsum(); + //komodo_interestsum(); komodo_longestchain(); MilliSleep(20000); } diff --git a/src/cc/CC made easy b/src/cc/CC made easy index 158c2907a..3f15a6b6b 100644 --- a/src/cc/CC made easy +++ b/src/cc/CC made easy @@ -95,7 +95,7 @@ EVAL(EVAL_DICE, 0xe6) \ EVAL(EVAL_FSM, 0xe7) \ EVAL(EVAL_AUCTION, 0xe8) \ EVAL(EVAL_LOTTO, 0xe9) \ -EVAL(EVAL_MOFN, 0xea) \ +EVAL(EVAL_HEIR, 0xea) \ EVAL(EVAL_CHANNELS, 0xeb) \ EVAL(EVAL_ORACLES, 0xec) \ EVAL(EVAL_PRICES, 0xed) \ diff --git a/src/cc/CCGateways.h b/src/cc/CCGateways.h index b584ba5d0..e82add62b 100644 --- a/src/cc/CCGateways.h +++ b/src/cc/CCGateways.h @@ -24,10 +24,11 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector pubkeys); std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vectorproof,CPubKey destpub,int64_t amount); std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount); -std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,std::vector withdrawpub,int64_t amount); +std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount); UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin); std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin,uint256 cointxid); -std::string GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr); +UniValue GatewaysMultisig(char *txidaddr); +std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin, std::string hex); // CCcustom UniValue GatewaysInfo(uint256 bindtxid); diff --git a/src/cc/CCMofN.h b/src/cc/CCHeir.h similarity index 89% rename from src/cc/CCMofN.h rename to src/cc/CCHeir.h index 170200d77..c86bf3b6b 100644 --- a/src/cc/CCMofN.h +++ b/src/cc/CCHeir.h @@ -14,16 +14,16 @@ ******************************************************************************/ -#ifndef CC_MOFN_H -#define CC_MOFN_H +#ifndef CC_HEIR_H +#define CC_HEIR_H #include "CCinclude.h" -#define EVAL_MOFN 0xea +#define EVAL_HEIR 0xea -bool MofNValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); +bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx); // CCcustom -UniValue MofNInfo(); +UniValue HeirInfo(); #endif diff --git a/src/cc/CCassetstx.cpp b/src/cc/CCassetstx.cpp index 5c933bd77..64b380900 100644 --- a/src/cc/CCassetstx.cpp +++ b/src/cc/CCassetstx.cpp @@ -17,15 +17,17 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs) { - char coinaddr[64],destaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t j,vout,n = 0; + char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t j,vout,n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); - + threshold = total/(maxinputs!=0?maxinputs:64); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; + if ( it->second.satoshis < threshold ) + continue; for (j=0; jvalidate = AuctionValidate; cp->ismyvin = IsAuctionInput; break; - case EVAL_MOFN: - strcpy(cp->unspendableCCaddr,MofNCCaddr); - strcpy(cp->normaladdr,MofNNormaladdr); - strcpy(cp->CChexstr,MofNCChexstr); - memcpy(cp->CCpriv,MofNCCpriv,32); - cp->validate = MofNValidate; - cp->ismyvin = IsMofNInput; + case EVAL_HEIR: + strcpy(cp->unspendableCCaddr,HeirCCaddr); + strcpy(cp->normaladdr,HeirNormaladdr); + strcpy(cp->CChexstr,HeirCChexstr); + memcpy(cp->CCpriv,HeirCCpriv,32); + cp->validate = HeirValidate; + cp->ismyvin = IsHeirInput; break; case EVAL_CHANNELS: strcpy(cp->unspendableCCaddr,ChannelsCCaddr); diff --git a/src/cc/CCdice.h b/src/cc/CCdice.h index 16b2f6136..8c67d86fe 100644 --- a/src/cc/CCdice.h +++ b/src/cc/CCdice.h @@ -24,7 +24,7 @@ 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 DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout); +std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyvout,int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout,uint256 vin0txid,int32_t vin0vout); 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); diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 2e447f485..f9924e173 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -48,9 +48,12 @@ one other technical note is that komodod has the insight-explorer extensions bui #include #include #include "../komodo_defs.h" +#include "../utlist.h" +#include "../uthash.h" extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE; extern uint32_t ASSETCHAINS_CC; +extern char ASSETCHAINS_SYMBOL[]; extern std::string CCerror; #define SMALLVAL 0.000000000000001 @@ -97,8 +100,8 @@ 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); +bool mytxid_inmempool(uint256 txid); int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout); -bool mySendrawtransaction(std::string res); int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp); int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *endianedp); @@ -124,7 +127,7 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv); // CCutils CPubKey buf2pk(uint8_t *buf33); void endiancpy(uint8_t *dest,uint8_t *src,int32_t len); -uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv); +uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout); CTxOut MakeCC1vout(uint8_t evalcode,CAmount nValue,CPubKey pk); CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk,CPubKey pk2); CC *MakeCCcond1(uint8_t evalcode,CPubKey pk); @@ -136,6 +139,7 @@ bool IsCCInput(CScript const& scriptSig); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); uint256 revuint256(uint256 txid); +bool pubkey2addr(char *destaddr,uint8_t *pubkey33); char *uint256_str(char *dest,uint256 txid); char *pubkey33_str(char *dest,uint8_t *pubkey33); uint256 Parseuint256(char *hexstr); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index f29fd05e8..320cd967d 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -17,12 +17,12 @@ /* FinalizeCCTx is a very useful function that will properly sign both CC and normal inputs, adds normal change and the opreturn. - + This allows the contract transaction functions to create the appropriate vins and vouts and have FinalizeCCTx create a properly signed transaction. - + By using -addressindex=1, it allows tracking of all the CC addresses */ - + bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScript scriptPubKey) { #ifdef ENABLE_WALLET @@ -33,9 +33,8 @@ bool SignTx(CMutableTransaction &mtx,int32_t vini,int64_t utxovalue,const CScrip UpdateTransaction(mtx,vini,sigdata); return(true); } else fprintf(stderr,"signing error for SignTx vini.%d %.8f\n",vini,(double)utxovalue/COIN); -#else - return(false); #endif + return(false); } std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey mypk,uint64_t txfee,CScript opret) @@ -276,6 +275,11 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t * abovei = belowi = -1; for (above=below=i=0; i 500 ) { + // if ( (rand() % 100) < 80 ) + // continue; + //} if ( (atx_value= utxos[i].nValue) <= 0 ) continue; if ( atx_value == value ) @@ -322,21 +326,26 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t * int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs) { - int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=1024; int64_t above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up; + int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up; #ifdef ENABLE_WALLET const CKeyStore& keystore = *pwalletMain; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos)); + threshold = total/maxinputs; + if ( maxinputs > maxutxos ) + maxutxos = maxinputs; + sum = 0; BOOST_FOREACH(const COutput& out, vecOutputs) { - if ( out.fSpendable != 0 ) + if ( out.fSpendable != 0 && out.tx->vout[out.i].nValue >= threshold ) { txid = out.tx->GetHash(); vout = out.i; - if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 ) + if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && vout < tx.vout.size() && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() == 0 ) { + //fprintf(stderr,"check %.8f to vins array.%d of %d %s/v%d\n",(double)out.tx->vout[out.i].nValue/COIN,n,maxutxos,txid.GetHex().c_str(),(int32_t)vout); if ( mtx.vin.size() > 0 ) { for (i=0; itxid = txid; up->nValue = out.tx->vout[out.i].nValue; up->vout = vout; + sum += up->nValue; //fprintf(stderr,"add %.8f to vins array.%d of %d\n",(double)up->nValue/COIN,n,maxutxos); - if ( n >= maxutxos ) + if ( n >= maxutxos || sum >= total ) break; } } diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index 491798a98..889b6fdd4 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -74,6 +74,7 @@ CC* GetCryptoCondition(CScript const& scriptSig) std::vector ffbin; if (scriptSig.GetOp(pc, opcode, ffbin)) return cc_readFulfillmentBinary((uint8_t*)ffbin.data(), ffbin.size()-1); + else return(0); } bool IsCCInput(CScript const& scriptSig) @@ -193,7 +194,7 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey) strcpy(destaddr,(char *)CBitcoinAddress(address).ToString().c_str()); return(true); } - fprintf(stderr,"ExtractDestination failed\n"); + //fprintf(stderr,"ExtractDestination failed\n"); return(false); } @@ -390,7 +391,7 @@ int64_t CCduration(int32_t &numblocks,uint256 txid) } else if ( hashBlock == zeroid ) { - fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid)); + //fprintf(stderr,"CCduration no hashBlock for txid %s\n",uint256_str(str,txid)); return(0); } else if ( (pindex= mapBlockIndex[hashBlock]) == 0 || (txtime= pindex->nTime) == 0 || (txheight= pindex->nHeight) <= 0 ) @@ -400,7 +401,8 @@ int64_t CCduration(int32_t &numblocks,uint256 txid) } else if ( (pindex= chainActive.LastTip()) == 0 || pindex->nTime < txtime || pindex->nHeight <= txheight ) { - fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->nHeight); + if ( pindex->nTime < txtime ) + fprintf(stderr,"CCduration backwards timestamps %u %u for txid %s hts.(%d %d)\n",(uint32_t)pindex->nTime,txtime,uint256_str(str,txid),txheight,(int32_t)pindex->nHeight); return(0); } numblocks = (pindex->nHeight - txheight); diff --git a/src/cc/assets.cpp b/src/cc/assets.cpp index 1ddbdc4f8..a421f9e44 100644 --- a/src/cc/assets.cpp +++ b/src/cc/assets.cpp @@ -249,8 +249,8 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx } fprintf(stderr,"fillbuy validated\n"); break; - case 'e': // selloffer - break; // disable swaps + //case 'e': // selloffer + // break; // disable swaps case 's': // selloffer //vin.0: normal input //vin.1+: valid CC output for sale @@ -322,6 +322,7 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx fprintf(stderr,"fill validated\n"); break; case 'E': // fillexchange + return eval->Invalid("unexpected assets fillexchange funcid"); break; // disable asset swaps //vin.0: normal input //vin.1: unspendable.(vout.0 assetoshis from selloffer) sellTx.vout[0] @@ -371,6 +372,10 @@ bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx } fprintf(stderr,"fill validated\n"); break; + default: + fprintf(stderr,"illegal assets funcid.(%c)\n",funcid); + return eval->Invalid("unexpected assets funcid"); + break; } return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); } diff --git a/src/cc/auction.cpp b/src/cc/auction.cpp index 7b5f106d0..d0d8db0bb 100644 --- a/src/cc/auction.cpp +++ b/src/cc/auction.cpp @@ -120,6 +120,7 @@ bool AuctionValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t int64_t AddAuctionInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) { + // add threshold check char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index bd0b5bb7f..a03a602d5 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -64,7 +64,7 @@ Possible third iteration: int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub, CPubKey destpub,int32_t v) { - char destaddr[64],channeladdr[64]; + char destaddr[65],channeladdr[65]; GetCCaddress1of2(cp,channeladdr,srcpub,destpub); if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) @@ -77,7 +77,7 @@ int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey int64_t IsChannelsMarkervout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub,int32_t v) { - char destaddr[64],ccaddr[64]; + char destaddr[65],ccaddr[65]; GetCCaddress(cp,ccaddr,srcpub); if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) @@ -348,8 +348,12 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & return eval->Invalid("invalid amount, refund amount and funds in channel must match!"); } break; + default: + fprintf(stderr,"illegal channels funcid.(%c)\n",funcid); + return eval->Invalid("unexpected channels funcid"); + break; } - } + } else return eval->Invalid("unexpected channels missing funcid"); retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts); if ( retval != 0 ) fprintf(stderr,"Channel tx validated\n"); @@ -364,7 +368,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, CTransaction openTx, uint256 &prevtxid) { - char coinaddr[64]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t param1; + char coinaddr[65]; int64_t param2,totalinputs = 0,numvouts; uint256 txid=zeroid,tmp_txid,hashBlock,param3; CTransaction tx; int32_t param1; std::vector > unspentOutputs; CPubKey srcpub,destpub; uint8_t myprivkey[32]; @@ -442,7 +446,7 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64 funds = numpayments * payment; if ( AddNormalinputs(mtx,mypk,funds+3*txfee,64) > 0 ) { - hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1); endiancpy(hash,(uint8_t *)&hentropy,32); for (i=0; i 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, txid, srcpub, destpub, param1, param2, param3) != 0) { - hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash); + hentropy = DiceHashEntropy(entropy, channelOpenTx.vin[0].prevout.hash, channelOpenTx.vin[0].prevout.n,1); endiancpy(hash, (uint8_t * ) & hentropy, 32); for (i = 0; i < param1; i++) { @@ -692,7 +696,7 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) UniValue ChannelsInfo(uint256 channeltxid) { UniValue result(UniValue::VOBJ); CTransaction tx,opentx; uint256 txid,tmp_txid,hashBlock,param3,opentxid,hashchain,prevtxid; - struct CCcontract_info *cp,C; char myCCaddr[64],addr[64],str1[256],str2[64]; int32_t vout,numvouts,param1,numpayments; + struct CCcontract_info *cp,C; char myCCaddr[65],addr[65],str1[512],str2[256]; int32_t vout,numvouts,param1,numpayments; int64_t nValue,param2,payment; CPubKey srcpub,destpub,mypk; std::vector > txids; @@ -768,4 +772,4 @@ UniValue ChannelsInfo(uint256 channeltxid) } } return(result); -} \ No newline at end of file +} diff --git a/src/cc/dapps/diceloop b/src/cc/dapps/diceloop new file mode 100755 index 000000000..44550b46a --- /dev/null +++ b/src/cc/dapps/diceloop @@ -0,0 +1,6 @@ +while true +do +./c dicestatus KMDICE 5be49570c56d036abb08b6d084da93a8a86f58fc48db4a1086be95540d752d6f + +sleep 10 +done diff --git a/src/cc/dapps/oraclefeed.c b/src/cc/dapps/oraclefeed.c index eaf488a34..a0930bae4 100644 --- a/src/cc/dapps/oraclefeed.c +++ b/src/cc/dapps/oraclefeed.c @@ -19,6 +19,8 @@ #include #include "cJSON.c" +bits256 zeroid; + char hexbyte(int32_t c) { c &= 0xf; @@ -139,7 +141,7 @@ long _stripwhite(char *buf,int accept) char *clonestr(char *str) { char *clone; - if ( str == 0 || str[0] == 0 ) + if ( str == 0 || str[0]==0) { printf("warning cloning nullstr.%p\n",str); //#ifdef __APPLE__ @@ -330,7 +332,8 @@ cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char system(cmdstr); *retstrp = 0; if ( (jsonstr= filestr(&fsize,fname)) != 0 ) - { + { + jsonstr[strlen(jsonstr)-1]='\0'; //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr); if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 ) *retstrp = jsonstr; @@ -357,7 +360,7 @@ bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson) retstr[64] = 0; decode_hex(txid.bytes,32,retstr); } - fprintf(stderr,"broadcast %s txid.(%s)\n",acname,bits256_str(str,txid)); + fprintf(stderr,"broadcast %s txid.(%s)\n",strlen(acname)>0?acname:refcoin,bits256_str(str,txid)); free(retstr); } } @@ -530,6 +533,23 @@ cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid) return(0); } +int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare) +{ + cJSON *retjson; char *retstr; int32_t res=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 ) + { + if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1; + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + + return (res); +} + void importaddress(char *refcoin,char *acname,char *depositaddr) { cJSON *retjson; char *retstr; @@ -545,6 +565,24 @@ void importaddress(char *refcoin,char *acname,char *depositaddr) } } +void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys,char *bindtxidstr) +{ + cJSON *retjson; char *retstr,Mstr[10],tmp[128]; + + sprintf(Mstr,"%d",M); + sprintf(tmp,"\"%s\"",bindtxidstr); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,tmp,"")) != 0 ) + { + fprintf(stderr,"unexpected addmultisigaddress json.(%s)\n",jprint(retjson,0)); + free(retstr); + } + else if ( retstr != 0 ) + { + printf("addmultisigaddress.(%s)\n",retstr); + free_json(retjson); + } +} + cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) { cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid; @@ -584,7 +622,7 @@ char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signerad return(0); } satoshis -= txfee; - sprintf(array,"[\"%s\"]",depositaddr); + sprintf(array,"\'[\"%s\"]\'",depositaddr); if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 ) { //createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...} @@ -599,9 +637,12 @@ char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signerad change = (total - satoshis); jaddnum(vouts,depositaddr,(double)change/SATOSHIDEN); } - char *argA,*argB; - argA = jprint(vins,1); - argB = jprint(vouts,1); + char *tmpA=jprint(vins,1); + char *tmpB=jprint(vouts,1); + char *argA=malloc(sizeof(char) * (strlen(tmpA)+3)); + char *argB=malloc(sizeof(char) * (strlen(tmpB)+3)); + sprintf(argA,"\'%s\'",tmpA); + sprintf(argB,"\'%s\'",tmpB); if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 ) { printf("createmultisig: unexpected JSON2.(%s)\n",jprint(retjson2,0)); @@ -609,10 +650,13 @@ char *createmultisig(char *refcoin,char *acname,char *depositaddr,char *signerad } else if ( txstr == 0 ) printf("createmultisig: null txstr and JSON2\n"); + free(tmpA); + free(tmpB); free(argA); free(argB); } } + free_json(retjson); } else if ( retstr != 0 ) { @@ -628,7 +672,7 @@ cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx char *retstr,*hexstr; cJSON *retjson; if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 ) { - if ( jint(retjson,"complete") != 0 ) + if ( is_cJSON_True(jobj(retjson,"complete")) != 0 ) return(retjson); else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) ) { @@ -640,18 +684,36 @@ cJSON *addmultisignature(char *refcoin,char *acname,char *signeraddr,char *rawtx return(0); } -char *get_gatewaysmultisig(char *refcoin,char *acname,char *bindtxidstr,char *withtxidstr,char *txidaddr) +char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K) { char *retstr,*hexstr,*hex=0; cJSON *retjson; - if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",bindtxidstr,refcoin,withtxidstr,txidaddr)) != 0 ) + if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",txidaddr,"","","")) != 0 ) { - if ( (hexstr= jstr(retjson,"hex")) != 0 ) - hex = clonestr(hexstr); + if ((hexstr=jstr(retjson,"hex")) != 0 ) + { + if (strlen(hexstr)>0) hex = clonestr(hexstr); + } + *K=jint(retjson,"number_of_signs"); free_json(retjson); } return(hex); } +bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex) +{ + char str[65],*retstr; cJSON *retjson; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 ) + { + return(komodobroadcast(refcoin,acname,retjson)); + } + else if ( retstr != 0 ) + { + printf("error parsing gatewayspartialsing.(%s)\n",retstr); + free(retstr); + } + return (zeroid); +} + void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin,bits256 cointxid) { char str[65],str2[65],*retstr; cJSON *retjson; @@ -668,9 +730,9 @@ void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin,bit } } -int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr) +int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys) { - char *oracle,*retstr,*name,*deposit; cJSON *retjson; + char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n; if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 ) { if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 ) @@ -680,9 +742,23 @@ int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *M { *Mp = jint(retjson,"M"); *Np = jint(retjson,"N"); - //printf("(%s)\n",jprint(retjson,0)); - } else printf("coin.%s vs %s\n",jstr(retjson,"coin"),coin); - } else printf("%s != %s\n",oracle,oraclestr); + } + else printf("coin.%s vs %s\n",jstr(retjson,"coin"),coin); + if ((pubarray=jarray(&n,retjson,"pubkeys"))!=0) + { + *pubkeys=malloc((sizeof(char)*70*n)+64); + sprintf(*pubkeys,"\"["); + for (int i=0;i","amount":0.0001},{"address":"","amount":}]' - txid = sendtoaddress("KMD",acname,txidaddr,10000); - if ( bits256_nonz(txid) != 0 && coinaddrexists("KMD",acname,txidaddr) > 0 ) + if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0) + { + // the actual withdraw + if ( strcmp(depositaddr,signeraddr) == 0 ) { - // the actual withdraw - if ( strcmp(depositaddr,signeraddr) == 0 ) + txid= sendtoaddress("KMD",acname,txidaddr,10000); + if (bits256_nonz(txid) != 0) { cointxid = sendtoaddress(refcoin,"",withdrawaddr,satoshis); - if ( bits256_nonz(cointxid) != 0 ) + if ( bits256_nonz(cointxid) != 0) { fprintf(stderr,"withdraw %s %s %s %.8f processed\n",refcoin,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); @@ -806,42 +909,40 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t } else { - if ( (rawtx= get_gatewaysmultisig(refcoin,acname,bindtxidstr,bits256_str(str,origtxid),txidaddr)) == 0 ) - { - rawtx = createmultisig(refcoin,"",depositaddr,signeraddr,withdrawaddr,satoshis); - } - if ( rawtx != 0 ) - { - if ( (clijson= addmultisignature(refcoin,"",signeraddr,rawtx)) != 0 ) - { - if ( jint(clijson,"complete") != 0 ) - { - cointxid = komodobroadcast(refcoin,"",clijson); - if ( bits256_nonz(cointxid) != 0 ) - { - fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); - gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); - } - } - else if ( jint(clijson,"partialtx") != 0 ) - { - // 10000 + ith -> txidaddr - txid = komodobroadcast("KMD",acname,clijson); - fprintf(stderr,"%s M.%d of N.%d partialtx %s sent\n",refcoin,M,N,bits256_str(str,txid)); - } - free_json(clijson); - } - processed++; - free(rawtx); - } else fprintf(stderr,"couldnt create msig rawtx\n"); + fprintf(stderr,"ERROR sending withdraw marker %s %s to %s %.8f processed\n",refcoin,bits256_str(str,cointxid),txidaddr,(double)10000/SATOSHIDEN); } } - } - else if ( retval > 0 ) - { - fprintf(stderr,"already did withdraw %s %s %.8f processed\n",refcoin,withdrawaddr,(double)satoshis/SATOSHIDEN); - gatewaysmarkdone("KMD",acname,origtxid,refcoin,zeroid); - } + else + { + if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0) + { + rawtx = createmultisig(refcoin,"",depositaddr,signeraddr,withdrawaddr,satoshis); + } + if ( rawtx != 0 ) + { + if ( (clijson= addmultisignature(refcoin,"",signeraddr,rawtx)) != 0 ) + { + if ( is_cJSON_True(jobj(clijson,"complete")) != 0 ) + { + cointxid = komodobroadcast(refcoin,"",clijson); + if ( bits256_nonz(cointxid) != 0 ) + { + fprintf(stderr,"withdraw %s M.%d N.%d %s %s %.8f processed\n",refcoin,M,N,bits256_str(str,cointxid),withdrawaddr,(double)satoshis/SATOSHIDEN); + gatewaysmarkdone("KMD",acname,origtxid,refcoin,cointxid); + } + } + else if ( jint(clijson,"partialtx") != 0 ) + { + txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex")); + fprintf(stderr,"%d of %d partialtx %s sent\n",K+1,N,bits256_str(str,txid)); + } + free_json(clijson); + } + processed++; + free(rawtx); + } else fprintf(stderr,"couldnt create msig rawtx\n"); + } + } } } } @@ -907,7 +1008,7 @@ oraclesdata 17a841a919c284cea8a676f34e793da002e606f19a9258a3190bed12d5aaa3ff 034 int32_t main(int32_t argc,char **argv) { - cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,M,N,n,height,prevheight = 0; char *format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid; + cJSON *clijson,*clijson2,*regjson,*item; int32_t acheight,i,retval,M,N,n,height,prevheight = 0; char *pubkeys,*format,*acname,*oraclestr,*bindtxidstr,*pkstr,*pubstr,*retstr,*retstr2,depositaddr[64],hexstr[4096],refcoin[64]; uint64_t price; bits256 txid; if ( argc < 6 ) { printf("usage: oraclefeed $ACNAME $ORACLETXID $MYPUBKEY $FORMAT $BINDTXID [refcoin_cli]\n"); @@ -943,12 +1044,18 @@ int32_t main(int32_t argc,char **argv) printf("need to specify path to refcoin's cli as last argv\n"); exit(0); } - if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr) < 0 ) + pubkeys=0; + if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) < 0 ) { printf("cant find bindtxid.(%s)\n",bindtxidstr); exit(0); } - importaddress(refcoin,"",depositaddr); + if (validateaddress(refcoin,"",depositaddr,"iswatchonly")==0) + { + if (M==N==1) importaddress(refcoin,"",depositaddr); + else addmultisigaddress(refcoin,"",M,pubkeys,bindtxidstr); + } + if (pubkeys!=0) free(pubkeys); printf("set refcoin %s <- %s [%s] M.%d of N.%d\n",depositaddr,refcoin,REFCOIN_CLI,M,N); } if ( (regjson= jarray(&n,clijson,"registered")) != 0 ) diff --git a/src/cc/dapps/sendmany b/src/cc/dapps/sendmany new file mode 100755 index 000000000..45560b505 --- /dev/null +++ b/src/cc/dapps/sendmany @@ -0,0 +1,3 @@ +export addr="RXgCPfi6wccRr3Eai3X9duTTkAirhcQLNo" +./komodo-cli -ac_name=KMDICE sendmany "" "{\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023,\"$addr\":0.023}" + diff --git a/src/cc/dice.cpp b/src/cc/dice.cpp index c90ec0f06..847fc5bee 100644 --- a/src/cc/dice.cpp +++ b/src/cc/dice.cpp @@ -85,84 +85,455 @@ WARNING: there is an attack vector that precludes betting any large amounts, it 3. reorg the chain and make a big bet using the winning entropy calculated in 2. In order to mitigate this, the disclosure of the house entropy needs to be delayed beyond a reasonable reorg depth (notarization). It is recommended for production dice game with significant amounts of money to use such a delayed disclosure method. + + Actually a much better solution to this is possible, which allows to retain the realtime response aspect of dice CC, which is critical to its usage. + +What is needed is for the dealer node to track the entropy tx that was already broadcast into the mempool with its entropy revealed. Then before processing a dicebet, it is checked against the already revealed list. If it is found, the dicebet is refunded with proof that a different dicebet was already used to reveal the entropy + + change to hashtables + validate refund + */ #include "../compat/endian.h" -static uint256 bettxids[128]; +#define MAX_ENTROPYUSED 8192 +#define DICE_MINUTXOS 7777 +extern int32_t KOMODO_INSYNC; + + +static uint256 bettxids[MAX_ENTROPYUSED],Entropyused[MAX_ENTROPYUSED][2]; // change to hashtable +static CTransaction betTxs[MAX_ENTROPYUSED]; +static int32_t entropyvouts[MAX_ENTROPYUSED]; + +pthread_mutex_t DICE_MUTEX,DICEREVEALED_MUTEX; + +struct dicefinish_utxo { uint256 txid; int32_t vout; }; struct dicefinish_info { - uint256 fundingtxid,bettxid; + struct dicefinish_info *prev,*next; + CTransaction betTx; + uint256 fundingtxid,bettxid,entropyused,txid; uint64_t sbits; - int32_t iswin; -}; + int64_t winamount; + int32_t iswin,entropyvout,orphaned; + uint32_t bettxid_ready,revealed; + std::string rawtx; + uint8_t funcid; +} *DICEFINISH_LIST; -bool mySendrawtransaction(std::string res) +int32_t _dicehash_find(uint256 bettxid) { - CTransaction tx; char str[65]; + int32_t i; + for (i=0; i 64 && is_hexstr((char *)res.c_str(),0) > 64 ) { 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 ) + if ( ptr != 0 ) + ptr->txid = tx.GetHash(); + //fprintf(stderr,"%s\n%s\n",res.c_str(),uint256_str(str,tx.GetHash())); + if ( funcid == 'R' || (retval= DiceEntropyUsed(oldbetTx,oldbettxid,oldentropyvout,entropyused,bettxid,betTx,entropyvout)) >= 0 ) { - RelayTransaction(tx); - fprintf(stderr,"added to mempool and broadcast\n"); - return(true); - } else fprintf(stderr,"error adding to mempool\n"); + //LOCK(cs_main); + if ( myAddtomempool(tx) != 0 ) + { + RelayTransaction(tx); + if ( retval == 0 ) + { + if ( ptr != 0 ) + ptr->revealed = (uint32_t)time(NULL); + pthread_mutex_lock(&DICEREVEALED_MUTEX); + _dicerevealed_add(entropyused,bettxid,betTx,entropyvout); + pthread_mutex_unlock(&DICEREVEALED_MUTEX); + fprintf(stderr,"added.%c to mempool.[%d] and broadcast entropyused.%s bettxid.%s -> %s\n",funcid,i,entropyused.GetHex().c_str(),bettxid.GetHex().c_str(),tx.GetHash().GetHex().c_str()); + } else fprintf(stderr,"rebroadcast.%c to mempool.[%d] and broadcast entropyused.%s bettxid.%s -> %s\n",funcid,i,entropyused.GetHex().c_str(),bettxid.GetHex().c_str(),tx.GetHash().GetHex().c_str()); + return(true); + } + else + { + RelayTransaction(tx); + fprintf(stderr,"rebroadcast.%c and clear [%d] and broadcast entropyused.%s bettxid.%s -> %s\n",funcid,i,entropyused.GetHex().c_str(),bettxid.GetHex().c_str(),tx.GetHash().GetHex().c_str()); + if ( ptr->rawtx.empty() == 0 ) + ptr->rawtx.clear(); + ptr->txid = zeroid; + //fprintf(stderr,"error adding funcid.%c E.%s bet.%s -> %s to mempool, probably Disable replacement feature size.%d\n",funcid,entropyused.GetHex().c_str(),bettxid.GetHex().c_str(),tx.GetHash().GetHex().c_str(),(int32_t)ptr->rawtx.size()); + } + } else fprintf(stderr,"error duplicate entropyused different bettxid\n"); } else fprintf(stderr,"error decoding hex\n"); } return(false); } -void *dicefinish(void *_ptr) +int32_t dicefinish_utxosget(int32_t &total,struct dicefinish_utxo *utxos,int32_t max,char *coinaddr) { - 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 ) + int32_t n = 0; int64_t threshold = 2 * 10000; + total = 0; + std::vector > unspentOutputs; + SetCCunspents(unspentOutputs,coinaddr); + { + LOCK(mempool.cs); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - duplicate = 1; - break; - } - if ( duplicate == 0 ) - { - for (i=0; ifirst.txhash,(int32_t)it->first.index) == 0 ) { - bettxids[i] = ptr->bettxid; - break; + if ( it->second.satoshis < threshold || it->second.satoshis > 10*threshold ) + continue; + total++; + if ( n < max ) + { + if ( utxos != 0 ) + { + utxos[n].txid = it->first.txhash; + utxos[n].vout = (int32_t)it->first.index; + } + n++; + } } - 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 ) + total -= n; + return(n); +} + +int32_t dice_betspent(char *debugstr,uint256 bettxid) +{ + CSpentIndexValue value,value2; + CSpentIndexKey key(bettxid,0); + CSpentIndexKey key2(bettxid,1); + if ( GetSpentIndex(key,value) != 0 || GetSpentIndex(key2,value2) != 0 ) { - res = DiceBetFinish(&result,0,name,ptr->fundingtxid,ptr->bettxid,ptr->iswin); - if ( result > 0 ) - mySendrawtransaction(res); + //fprintf(stderr,"%s txid.%s already spent\n",debugstr,bettxid.GetHex().c_str()); + return(1); + } + { + //LOCK(mempool.cs); + if ( myIsutxo_spentinmempool(bettxid,0) != 0 || myIsutxo_spentinmempool(bettxid,1) != 0 ) + { + fprintf(stderr,"%s bettxid.%s already spent in mempool\n",debugstr,bettxid.GetHex().c_str()); + return(-1); + } } - free(ptr); return(0); } -void DiceQueue(int32_t iswin,uint64_t sbits,uint256 fundingtxid,uint256 bettxid) +void dicefinish_delete(struct dicefinish_info *ptr) { - 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 ) + pthread_mutex_lock(&DICE_MUTEX); + _dicehash_clear(ptr->bettxid); + pthread_mutex_unlock(&DICE_MUTEX); + DL_DELETE(DICEFINISH_LIST,ptr); + free(ptr); +} + +void *dicefinish(void *_ptr) +{ + std::vector mypk; struct CCcontract_info *cp,C; char name[32],coinaddr[64],CCaddr[64]; std::string res; int32_t newht,newblock,entropyvout,numblocks,lastheight=0,vin0_needed,n,m,num,iter,result; struct dicefinish_info *ptr,*tmp; uint32_t now; struct dicefinish_utxo *utxos; uint256 hashBlock,entropyused; CTransaction betTx,finishTx; + mypk = Mypubkey(); + pubkey2addr(coinaddr,mypk.data()); + cp = CCinit(&C,EVAL_DICE); + GetCCaddress(cp,CCaddr,GetUnspendable(cp,0)); + fprintf(stderr,"start dicefinish thread %s CCaddr.%s\n",coinaddr,CCaddr); + if ( (newht= KOMODO_INSYNC) == 0 ) + sleep(7); + sleep(3); + while ( 1 ) { - //fprintf(stderr,"DiceQueue.%d\n",iswin); - } // small memory leak per DiceQueue + if ( newht != 0 && lastheight != newht ) + { + lastheight = newht; + newblock = 1; + fprintf(stderr,"dicefinish process lastheight.%d <- newht.%d\n",lastheight,newht); + } else newblock = 0; + now = (uint32_t)time(NULL); + for (iter=-1; iter<=1; iter+=2) + { + vin0_needed = 0; + DL_FOREACH_SAFE(DICEFINISH_LIST,ptr,tmp) + { + if ( ptr->iswin != iter ) + continue; + if ( ptr->revealed != 0 && now > ptr->revealed+3600 ) + { + fprintf(stderr,"purge %s\n",ptr->bettxid.GetHex().c_str()); + dicefinish_delete(ptr); + continue; + } + if ( ptr->bettxid_ready == 0 ) + { + if ( myGetTransaction(ptr->bettxid,betTx,hashBlock) != 0 && hashBlock != zeroid ) + ptr->bettxid_ready = (uint32_t)time(NULL); + else if ( mytxid_inmempool(ptr->bettxid) != 0 ) + ptr->bettxid_ready = (uint32_t)time(NULL); + } + else if ( newblock != 0 && myGetTransaction(ptr->bettxid,betTx,hashBlock) == 0 ) + { + fprintf(stderr,"ORPHANED bettxid.%s\n",ptr->bettxid.GetHex().c_str()); + dicefinish_delete(ptr); + continue; + } + else if ( newblock != 0 && ptr->txid != zeroid ) + { + if ( myGetTransaction(ptr->txid,finishTx,hashBlock) == 0 ) + { + ptr->orphaned++; + fprintf(stderr,"ORPHANED.%d finish txid.%s\n",ptr->orphaned,ptr->txid.GetHex().c_str()); + if ( ptr->orphaned < 3 ) + continue; + if ( ptr->rawtx.empty() == 0 ) + ptr->rawtx.clear(); + ptr->txid = zeroid; + unstringbits(name,ptr->sbits); + result = 0; + ptr->orphaned = 0; + res = DiceBetFinish(ptr->funcid,entropyused,entropyvout,&result,0,name,ptr->fundingtxid,ptr->bettxid,ptr->iswin,zeroid,-2); + if ( ptr->entropyused == zeroid ) + { + ptr->entropyused = entropyused; + ptr->entropyvout = entropyvout; + } + if ( entropyused != ptr->entropyused || entropyvout != ptr->entropyvout ) + { + fprintf(stderr,"WARNING entropy %s != %s || %d != %d\n",entropyused.GetHex().c_str(),ptr->entropyused.GetHex().c_str(),entropyvout,ptr->entropyvout); + } + if ( result > 0 ) + { + ptr->rawtx = res; + fprintf(stderr,"send refund!\n"); + mySenddicetransaction(ptr->rawtx,ptr->entropyused,ptr->entropyvout,ptr->bettxid,ptr->betTx,ptr->funcid,ptr); + } + continue; + } + } + if ( ptr->bettxid_ready != 0 ) + { + if ( newblock != 0 && ptr->txid != zeroid ) + { + CCduration(numblocks,ptr->txid); + //fprintf(stderr,"duration finish txid.%s\n",ptr->txid.GetHex().c_str()); + if ( numblocks == 0 ) + mySenddicetransaction(ptr->rawtx,ptr->entropyused,ptr->entropyvout,ptr->bettxid,ptr->betTx,ptr->funcid,ptr); + else continue; + } + if ( ptr->txid == zeroid ) + vin0_needed++; + } + } + if ( vin0_needed > 0 ) + { + num = 0; + //fprintf(stderr,"iter.%d vin0_needed.%d\n",iter,vin0_needed); + utxos = (struct dicefinish_utxo *)calloc(vin0_needed,sizeof(*utxos)); + if ( (n= dicefinish_utxosget(num,utxos,vin0_needed,coinaddr)) > 0 ) + { + //fprintf(stderr,"iter.%d vin0_needed.%d got %d\n",iter,vin0_needed,n); + m = 0; + DL_FOREACH_SAFE(DICEFINISH_LIST,ptr,tmp) + { + if ( ptr->iswin != iter ) + continue; + if ( ptr->revealed != 0 && time(NULL) > ptr->revealed+3600 ) + { + fprintf(stderr,"purge2 %s\n",ptr->bettxid.GetHex().c_str()); + dicefinish_delete(ptr); + continue; + } + if ( ptr->txid != zeroid ) + { + CCduration(numblocks,ptr->txid); + //fprintf(stderr,"numblocks %s %d\n",ptr->txid.GetHex().c_str(),numblocks); + if ( numblocks > 0 ) + continue; + } + if ( ptr->bettxid_ready != 0 && ptr->rawtx.size() == 0 && dice_betspent((char *)"dicefinish",ptr->bettxid) <= 0 && ptr->txid == zeroid ) + { + unstringbits(name,ptr->sbits); + result = 0; + res = DiceBetFinish(ptr->funcid,entropyused,entropyvout,&result,0,name,ptr->fundingtxid,ptr->bettxid,ptr->iswin,utxos[m].txid,utxos[m].vout); + if ( ptr->entropyused == zeroid ) + { + ptr->entropyused = entropyused; + ptr->entropyvout = entropyvout; + } + if ( entropyused != ptr->entropyused || entropyvout != ptr->entropyvout ) + { + fprintf(stderr,"WARNING entropy %s != %s || %d != %d\n",entropyused.GetHex().c_str(),ptr->entropyused.GetHex().c_str(),entropyvout,ptr->entropyvout); + } + if ( result > 0 ) + { + ptr->rawtx = res; + mySenddicetransaction(ptr->rawtx,ptr->entropyused,ptr->entropyvout,ptr->bettxid,ptr->betTx,ptr->funcid,ptr); + } + else if ( result != -2 ) + { + fprintf(stderr,"error doing the dicefinish %d of %d process %s %s using %s/v%d need %.8f\n",m,n,iter<0?"loss":"win",ptr->bettxid.GetHex().c_str(),utxos[m].txid.GetHex().c_str(),utxos[m].vout,(double)(iter<0 ? 0 : ptr->winamount)/COIN); + if ( ptr->rawtx.empty() == 0 ) + ptr->rawtx.clear(); + ptr->txid = zeroid; + } + if ( ++m >= n ) + break; + } + else + { + //fprintf(stderr,"error ready.%d dicefinish %d of %d process %s %s using need %.8f finish.%s size.%d betspent.%d\n",ptr->bettxid_ready,m,n,iter<0?"loss":"win",ptr->bettxid.GetHex().c_str(),(double)(iter<0 ? 0 : ptr->winamount)/COIN,ptr->txid.GetHex().c_str(),(int32_t)ptr->rawtx.size(),dice_betspent((char *)"dicefinish",ptr->bettxid)); + } + } + } + else if ( newblock != 0 ) + dicefinish_utxosget(num,0,0,coinaddr); + free(utxos); + if ( newblock != 0 && num < DICE_MINUTXOS ) + { + char *cmd = (char *)malloc(100 * 128); + sprintf(cmd,"./komodo-cli -ac_name=%s sendmany \"\" \"{\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002,\\\"%s\\\":0.0002}\"",ASSETCHAINS_SYMBOL,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr,coinaddr); + fprintf(stderr,"num normal 0.0002 utxos.%d < %d\n",num,DICE_MINUTXOS); + if ( system(cmd) != 0 ) + fprintf(stderr,"system error issuing.(%s)\n",cmd); + free(cmd); + if ( (rand() % 100) == 0 ) + { + fprintf(stderr,"make 0.023 utxos\n"); + if ( system("cc/dapps/sendmany") != 0 ) + fprintf(stderr,"system error issuing.(cc/dapps/sendmany)\n"); + } + } + } + } + if ( (newht= KOMODO_INSYNC) == 0 || newht == lastheight ) + sleep(3); + else usleep(500000); + } + return(0); +} + +void DiceQueue(int32_t iswin,uint64_t sbits,uint256 fundingtxid,uint256 bettxid,CTransaction betTx,int32_t entropyvout) +{ + static int32_t didinit; + struct dicefinish_info *ptr; int32_t i,duplicate=0; uint64_t txfee = 10000; + if ( didinit == 0 ) + { + if ( pthread_create((pthread_t *)malloc(sizeof(pthread_t)),NULL,dicefinish,0) == 0 ) + { + pthread_mutex_init(&DICE_MUTEX,NULL); + pthread_mutex_init(&DICEREVEALED_MUTEX,NULL); + didinit = 1; + } + else + { + fprintf(stderr,"error launching dicefinish thread\n"); + return; + } + } + //if ( dice_betspent((char *)"DiceQueue",bettxid) != 0 ) + // return; + pthread_mutex_lock(&DICE_MUTEX); + if ( _dicehash_find(bettxid) == 0 ) + { + _dicehash_add(bettxid); + ptr = (struct dicefinish_info *)calloc(1,sizeof(*ptr)); + ptr->fundingtxid = fundingtxid; + ptr->bettxid = bettxid; + ptr->betTx = betTx; + ptr->sbits = sbits; + ptr->iswin = iswin; + ptr->winamount = betTx.vout[1].nValue * ((betTx.vout[2].nValue - txfee)+1); + ptr->entropyvout = entropyvout; + DL_APPEND(DICEFINISH_LIST,ptr); + fprintf(stderr,"queued iswin.%d %.8f -> %.8f %s\n",iswin,(double)betTx.vout[1].nValue/COIN,(double)ptr->winamount/COIN,bettxid.GetHex().c_str()); + } + else + { + //fprintf(stderr,"DiceQueue status bettxid.%s already in list\n",bettxid.GetHex().c_str()); + //_dicehash_clear(bettxid); + } + pthread_mutex_unlock(&DICE_MUTEX); } CPubKey DiceFundingPk(CScript scriptPubKey) @@ -178,11 +549,16 @@ CPubKey DiceFundingPk(CScript scriptPubKey) return(pk); } -uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv) // max 1 vout per txid used +uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t vout,int32_t usevout) { 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); + if ( usevout != 0 ) + { + txidpriv.bytes[1] ^= (vout & 0xff); + txidpriv.bytes[2] ^= ((vout>>8) & 0xff); + } txidpriv.bytes[0] &= 0xf8, txidpriv.bytes[31] &= 0x7f, txidpriv.bytes[31] |= 0x40; txidpub = curve25519(txidpriv,curve25519_basepoint9()); @@ -219,12 +595,15 @@ int32_t dice_5nibbles(uint8_t *fivevals) return(((int32_t)fivevals[0]<<16) + ((int32_t)fivevals[1]<<12) + ((int32_t)fivevals[2]<<8) + ((int32_t)fivevals[3]<<4) + ((int32_t)fivevals[4])); } -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) +uint64_t DiceCalc(int64_t bet,int64_t vout2,int64_t minbet,int64_t maxbet,int64_t maxodds,int64_t timeoutblocks,uint256 houseentropy,uint256 bettorentropy) { - uint8_t buf[64],_house[32],_bettor[32],_hash[32],hash[32],hash16[64]; uint64_t winnings; arith_uint256 house,bettor; char str[65],str2[65]; int32_t i,modval; - if ( odds < 10000 ) + uint8_t buf[64],_house[32],_bettor[32],_hash[32],hash[32],hash16[64]; uint64_t odds,winnings; arith_uint256 house,bettor; char str[65],str2[65]; int32_t i,modval; + if ( vout2 <= 10000 ) + { + fprintf(stderr,"unexpected vout2.%llu\n",(long long)vout2); return(0); - else odds -= 10000; + } + else odds = (vout2 - 10000); if ( bet < minbet || bet > maxbet ) { CCerror = strprintf("bet size violation %.8f",(double)bet/COIN); @@ -237,7 +616,6 @@ uint64_t DiceCalc(int64_t bet,int64_t odds,int64_t minbet,int64_t maxbet,int64_t fprintf(stderr,"%s\n", CCerror.c_str() ); 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); @@ -249,6 +627,7 @@ uint64_t DiceCalc(int64_t bet,int64_t odds,int64_t minbet,int64_t maxbet,int64_t vcalc_sha256(0,(uint8_t *)&_bettor,buf,64); endiancpy((uint8_t *)&bettor,_bettor,32); winnings = 0; + //fprintf(stderr,"calc house entropy %s vs bettor %s\n",uint256_str(str,*(uint256 *)&house),uint256_str(str2,*(uint256 *)&bettor)); if ( odds > 1 ) { if ( 0 ) @@ -279,7 +658,7 @@ uint64_t DiceCalc(int64_t bet,int64_t odds,int64_t minbet,int64_t maxbet,int64_t break; } } - fprintf(stderr,"modval %d vs %d\n",modval,(int32_t)(10000/(odds+1))); + //fprintf(stderr,"modval %d vs %d\n",modval,(int32_t)(10000/(odds+1))); if ( modval < 10000/(odds+1) ) winnings = bet * (odds+1); } @@ -318,8 +697,10 @@ CScript EncodeDiceOpRet(uint8_t funcid,uint64_t sbits,uint256 fundingtxid,uint25 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,timeoutblocks; + //script = (uint8_t *)scriptPubKey.data(); + //fprintf(stderr,"decode %02x %02x %02x\n",script[0],script[1],script[2]); GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 ) + if ( vopret.size() > 2 )//&& script[0] == 0x6a ) { script = (uint8_t *)vopret.data(); if ( script[0] == EVAL_DICE ) @@ -335,7 +716,7 @@ uint8_t DecodeDiceOpRet(uint256 txid,const CScript &scriptPubKey,uint64_t &sbits } else if ( E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> sbits; ss >> fundingtxid; ss >> hash; ss >> proof) != 0 ) { - if ( e == EVAL_DICE && (f == 'B' || f == 'W' || f == 'L' || f == 'T' || f == 'E') ) + if ( e == EVAL_DICE && (f == 'R' || f == 'B' || f == 'W' || f == 'L' || f == 'T' || f == 'E') ) return(f); else fprintf(stderr,"mismatched e.%02x f.(%c)\n",e,f); } @@ -380,7 +761,7 @@ int64_t DiceAmounts(uint64_t &inputs,uint64_t &outputs,struct CCcontract_info *c return eval->Invalid("always should find vin, but didnt"); else { - if ( (assetoshis= IsDicevout(cp,vinTx,tx.vin[i].prevout.n,refsbits,reffundingtxid)) != 0 ) + if ( (assetoshis= IsDicevout(cp,vinTx,(int32_t)tx.vin[i].prevout.n,refsbits,reffundingtxid)) != 0 ) inputs += assetoshis; } } @@ -402,7 +783,7 @@ bool DiceIsmine(const CScript scriptPubKey) 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) +int32_t DiceIsWinner(uint256 &entropy,int32_t &entropyvout,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]; @@ -410,11 +791,18 @@ int32_t DiceIsWinner(uint256 &entropy,uint256 txid,CTransaction tx,CTransaction { 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); + hentropy2 = DiceHashEntropy(entropy,vinTx.vin[0].prevout.hash,vinTx.vin[0].prevout.n,0); + entropyvout = vinTx.vin[0].prevout.n; + //fprintf(stderr,"bettxid %s -> vin0 %s/v%d -> %s\n",txid.GetHex().c_str(),vinTx.vin[0].prevout.hash.GetHex().c_str(),entropyvout,entropy.GetHex().c_str()); + if ( hentropy != hentropy2 ) + { + hentropy2 = DiceHashEntropy(entropy,vinTx.vin[0].prevout.hash,vinTx.vin[0].prevout.n,1); + //fprintf(stderr,"alt bettxid %s -> vin0 %s/v%d -> %s\n",txid.GetHex().c_str(),vinTx.vin[0].prevout.hash.GetHex().c_str(),entropyvout,entropy.GetHex().c_str()); + } 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)); + //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 ) { @@ -426,9 +814,13 @@ int32_t DiceIsWinner(uint256 &entropy,uint256 txid,CTransaction tx,CTransaction // queue 'W' winning tx return(1); } - } else fprintf(stderr,"hentropy != hentropy2\n"); + } + else + { + fprintf(stderr,"both 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"); + } //else fprintf(stderr,"notmine.%d or not CC.%d\n",DiceIsmine(vinTx.vout[1].scriptPubKey) != 0,vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0); return(0); } @@ -442,7 +834,7 @@ bool DiceVerifyTimeout(CTransaction &betTx,int32_t timeoutblocks) 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]; + uint256 txid,fundingtxid,vinfundingtxid,vinhentropy,vinproof,hashBlock,hash,proof,entropy; int64_t minbet,maxbet,maxodds,timeoutblocks,odds,winnings; uint64_t vinsbits,refsbits=0,sbits,amount,inputs,outputs,txfee=10000; int32_t numvins,entropyvout,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; @@ -451,7 +843,7 @@ 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,hash,proof)) != 0 ) + if ( (funcid= DecodeDiceOpRet(txid,tx.vout[numvouts-1].scriptPubKey,refsbits,fundingtxid,hash,proof)) != 0 ) { if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 ) return eval->Invalid("cant find fundingtxid"); @@ -460,6 +852,11 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) if ( maxodds > 9999 ) return eval->Invalid("maxodds too big"); fundingPubKey = fundingTx.vout[1].scriptPubKey; + if ( sbits != refsbits ) + { + fprintf(stderr,"VALIDATION ERROR: sbits %llx != refsbits %llx\n",(long long)sbits,(long long)refsbits); + //return eval->Invalid("mismatched diceplan"); + } switch ( funcid ) { case 'F': @@ -498,37 +895,51 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) 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 ) + else if ( ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,(int64_t)vinTx.vout[tx.vin[0].prevout.n].nValue) == 0 ) + { + fprintf(stderr,"%s prevout.%d %.8f\n",tx.vin[0].prevout.hash.GetHex().c_str(),(int32_t)tx.vin[0].prevout.n,(double)vinTx.vout[tx.vin[0].prevout.n].nValue/COIN); 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 ) + 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 ) + if ( (int32_t)vinTx.vin[0].prevout.n < 0 || 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"); + uint8_t *ptr0,*ptr1; int32_t i; char str[65],addr0[64],addr1[64]; + Getscriptaddress(addr0,vinofvinTx.vout[vinTx.vin[0].prevout.n].scriptPubKey); + Getscriptaddress(addr1,fundingPubKey); + if ( strcmp(addr0,addr1) != 0 ) + { + fprintf(stderr,"%s != %s betTx.%s\n",addr0,addr1,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 ) + if ( (iswin= DiceIsWinner(entropy,entropyvout,txid,tx,vinTx,hash,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 ) { // will only happen for fundingPubKey - DiceQueue(iswin,sbits,fundingtxid,txid); + if ( KOMODO_INSYNC != 0 ) + DiceQueue(iswin,sbits,fundingtxid,txid,tx,entropyvout); + } + else + { + //fprintf(stderr,"why does node1 get VALIDATION ERROR: invalid dicebet bettxid %s\n",txid.GetHex().c_str()); + //return eval->Invalid("invalid dicebet bettxid"); } break; // make sure all funding txid are from matching sbits and fundingtxid!! @@ -581,7 +992,7 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) 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); + fprintf(stderr,"inputs %.8f != outputs %.8f (%.8f %.8f %.8f %.8f)\n",(double)inputs/COIN,(double)outputs/COIN,(double)tx.vout[0].nValue/COIN,(double)tx.vout[1].nValue/COIN,(double)tx.vout[2].nValue/COIN,(double)tx.vout[3].nValue/COIN); return eval->Invalid("CC funds mismatch for win/timeout"); } else if ( tx.vout[3].scriptPubKey != fundingPubKey ) @@ -605,8 +1016,29 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) else if ( DiceVerifyTimeout(vinTx,timeoutblocks) == 0 ) return eval->Invalid("invalid timeout claim for timeout"); break; + case 'R': + if ( eval->GetTxUnconfirmed(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 ) + return eval->Invalid("always should find vin.0, but didnt for refund"); + else if ( vinTx.vout[tx.vin[0].prevout.n].scriptPubKey != fundingPubKey ) + { + char fundingaddr[64],cmpaddr[64]; + Getscriptaddress(fundingaddr,fundingPubKey); + Getscriptaddress(cmpaddr,vinTx.vout[tx.vin[0].prevout.n].scriptPubKey); + if ( strcmp(cmpaddr,fundingaddr) != 0 ) + { + fprintf(stderr,"cmpaddr.%s != fundingaddr.%s\n",cmpaddr,fundingaddr); + return eval->Invalid("vin.0 not from fundingPubKey for refund"); + } + } + if ( (rand() % 1000) == 0 ) + fprintf(stderr,"add more validation for refunds\n"); + break; + default: + fprintf(stderr,"illegal dice funcid.(%c)\n",funcid); + return eval->Invalid("unexpected dice funcid"); + break; } - } + } else return eval->Invalid("unexpected dice missing funcid"); return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); } return(true); @@ -614,15 +1046,18 @@ bool DiceValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction &tx) uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint64_t total,int32_t maxinputs,uint64_t refsbits,uint256 reffundingtxid) { - 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; + char coinaddr[64],str[65]; uint64_t threshold,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); + if ( maxinputs > 0 ) + threshold = total / maxinputs; + else threshold = total / 64; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; - if ( it->second.satoshis < 1000000 ) + if ( vout != 0 || it->second.satoshis < threshold ) 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 && myIsutxo_spentinmempool(txid,vout) == 0 ) + if ( myGetTransaction(txid,tx,hashBlock) != 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,hash,proof)) != 0 ) { char str[65],sstr[16]; unstringbits(sstr,sbits); - fprintf(stderr,"(%c) %.8f %s %s\n",funcid,(double)tx.vout[0].nValue/COIN,sstr,uint256_str(str,txid)); if ( sbits == refsbits && (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid ) { if ( funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T' ) { if ( total != 0 && maxinputs != 0 ) + { + fprintf(stderr,"use (%c) %.8f %s %s/v%d\n",funcid,(double)tx.vout[0].nValue/COIN,sstr,uint256_str(str,txid),vout); mtx.vin.push_back(CTxIn(txid,vout,CScript())); + } totalinputs += it->second.satoshis; n++; if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) ) @@ -655,65 +1092,97 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK return(totalinputs); } -int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey dicepk,uint256 reffundingtxid,int32_t &entropytxs) +int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbits,struct CCcontract_info *cp,CPubKey dicepk,uint256 reffundingtxid, int32_t &entropytxs,bool random) { - char coinaddr[64],str[65]; uint64_t sbits; int64_t nValue,totalinputs = 0; uint256 hash,txid,proof,hashBlock,fundingtxid; CScript fundingPubKey; CTransaction tx,vinTx; int32_t vout,first=0,n=0; uint8_t funcid; + char coinaddr[64],str[65]; uint64_t sbits; int64_t nValue,sum,totalinputs = 0; uint256 hash,txid,proof,hashBlock,fundingtxid; CScript fundingPubKey; CTransaction tx,vinTx; int32_t vout,first=0,n=0,i=0,pendingbets=0; uint8_t funcid; std::vector > unspentOutputs; entropyval = 0; entropytxid = zeroid; - if ( GetTransaction(reffundingtxid,tx,hashBlock,false) != 0 && tx.vout.size() > 1 && ConstrainVout(tx.vout[0],1,cp->unspendableCCaddr,0) != 0 ) + if ( myGetTransaction(reffundingtxid,tx,hashBlock) != 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; + int loops = 0; + int numtxs = unspentOutputs.size()/2; + int startfrom = rand() % (numtxs+1); 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 && myIsutxo_spentinmempool(txid,vout) == 0 ) + if ( vout != 0 ) + continue; + sum += it->second.satoshis; + loops++; + if (random) { + if ( loops < startfrom ) + continue; + if ( (rand() % 100) < 90 ) + continue; + } + if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - //char str[65],str2[65]; - if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 ) + if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 && sbits == refsbits ) { + if ( funcid == 'B' ) + { + pendingbets++; + fprintf(stderr,"%d: %s/v%d (%c %.8f) %.8f %.8f\n",n,uint256_str(str,txid),vout,funcid,(double)it->second.satoshis/COIN,(double)totalinputs/COIN,(double)sum/COIN); + } if ( (funcid == 'F' && reffundingtxid == txid) || reffundingtxid == fundingtxid ) { - if ( refsbits == sbits && (nValue= IsDicevout(cp,tx,vout,refsbits,reffundingtxid)) > 10000 && (funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T') ) + //fprintf(stderr,"%d: %s/v%d (%c %.8f) %.8f %.8f\n",n,uint256_str(str,txid),vout,funcid,(double)it->second.satoshis/COIN,(double)totalinputs/COIN,(double)sum/COIN); + if ( (nValue= IsDicevout(cp,tx,vout,refsbits,reffundingtxid)) >= 10000 && (funcid == 'F' || funcid == 'E' || funcid == 'W' || funcid == 'L' || funcid == 'T') ) { - fprintf(stderr,"%s.(%c %.8f) ",uint256_str(str,txid),funcid,(double)nValue/COIN); - if ( funcid != 'F' && funcid != 'T' ) + if ( funcid == 'L' || funcid == 'W' || funcid == 'E' ) n++; totalinputs += nValue; if ( first == 0 && (funcid == 'E' || funcid == 'W' || funcid == 'L') ) { - fprintf(stderr,"check first\n"); - if ( fundingPubKey == tx.vout[1].scriptPubKey ) + //fprintf(stderr,"check first\n"); + if ( tx.vout.size() > 1 && fundingPubKey == tx.vout[1].scriptPubKey ) { - if ( funcid == 'E' && fundingtxid != tx.vin[0].prevout.hash ) + if ( myGetTransaction(tx.vin[0].prevout.hash,vinTx,hashBlock) == 0 || (int32_t)tx.vin[0].prevout.n < 0 ) { - if ( GetTransaction(tx.vin[0].prevout.hash,vinTx,hashBlock,false) == 0 ) + fprintf(stderr,"cant find entropy vin0 %s or vin0prev %d vouts[%d], iscoinbase.%d\n",uint256_str(str,tx.vin[0].prevout.hash),(int32_t)tx.vin[0].prevout.n,(int32_t)vinTx.vout.size(),(int32_t)vinTx.vin.size()); + continue; + } + if ( (int32_t)vinTx.vin[0].prevout.n < 0 || vinTx.vout.size() < 2 ) + { + fprintf(stderr,"skip coinbase or strange entropy tx\n"); + continue; + } + //if ( fundingtxid != tx.vin[0].prevout.hash && vinTx.vout[tx.vin[0].prevout.n].scriptPubKey != fundingPubKey ) + if ( fundingtxid != tx.vin[0].prevout.hash && vinTx.vout[1].scriptPubKey != fundingPubKey ) + { + uint8_t *ptr0,*ptr1; int32_t i; char str[65],addr0[64],addr1[64]; + Getscriptaddress(addr0,vinTx.vout[1].scriptPubKey); + Getscriptaddress(addr1,fundingPubKey); + if ( strcmp(addr0,addr1) != 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(); + ptr0 = (uint8_t *)vinTx.vout[1].scriptPubKey.data(); ptr1 = (uint8_t *)fundingPubKey.data(); - for (i=0; i 1 && ConstrainVout(tx.vout[0],1,CCaddr,0) != 0 ) + if ( myGetTransaction(fundingtxid,tx,hashBlock) != 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 ) { @@ -763,7 +1241,7 @@ bool DicePlanExists(CScript &fundingPubKey,uint256 &fundingtxid,struct CCcontrac 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 ( myGetTransaction(txid,tx,hashBlock) != 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,timeoutblocks) == 'F' ) { @@ -802,7 +1280,7 @@ struct CCcontract_info *Diceinit(CScript &fundingPubKey,uint256 reffundingtxid,s UniValue DiceInfo(uint256 diceid) { 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 ) + if ( myGetTransaction(diceid,vintx,hashBlock) == 0 ) { fprintf(stderr,"cant find fundingtxid\n"); ERR_RESULT("cant find fundingtxid"); @@ -827,11 +1305,11 @@ UniValue DiceInfo(uint256 diceid) result.push_back(Pair("timeoutblocks",timeoutblocks)); cp = CCinit(&C,EVAL_DICE); dicepk = GetUnspendable(cp,0); - int32_t entropytxs = 0; - funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,diceid,entropytxs); - result.push_back(Pair("entropytxs",entropytxs)); + int32_t entropytxs; + funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,diceid,entropytxs,false); sprintf(numstr,"%.8f",(double)funding/COIN); result.push_back(Pair("funding",numstr)); + result.push_back(Pair("entropytxs",entropytxs)); return(result); } @@ -843,7 +1321,7 @@ UniValue DiceList() for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) { txid = it->first.txhash; - if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) + if ( myGetTransaction(txid,vintx,hashBlock) != 0 ) { if ( vintx.vout.size() > 0 && DecodeDiceFundingOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey,sbits,minbet,maxbet,maxodds,timeoutblocks) != 0 ) { @@ -857,7 +1335,7 @@ UniValue DiceList() 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; 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 || maxodds > 9999 || timeoutblocks < 0 || timeoutblocks > 1440 ) + if ( funds < 0 || minbet < 0 || maxbet < 0 || maxodds < 2 || maxodds > 9999 || timeoutblocks < 0 || timeoutblocks > 1440 ) { CCerror = "invalid parameter error"; fprintf(stderr,"%s\n", CCerror.c_str() ); @@ -916,9 +1394,9 @@ std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int6 } if ( scriptPubKey == fundingPubKey ) { - if ( AddNormalinputs(mtx,mypk,amount+2*txfee,60) > 0 ) + if ( AddNormalinputs(mtx,mypk,amount+2*txfee,1) > 0 ) { - hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1); 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))); @@ -935,60 +1413,77 @@ std::string DiceAddfunding(uint64_t txfee,char *planstr,uint256 fundingtxid,int6 std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet,int32_t odds) { - 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; + CMutableTransaction mtx; CScript fundingPubKey; CPubKey mypk,dicepk; uint64_t sbits,entropyval,entropyval2; int64_t funding,minbet,maxbet,maxodds,timeoutblocks; uint256 entropytxid,entropytxid2,entropy,hentropy; struct CCcontract_info *cp,C; if ( bet < 0 ) { CCerror = "bet must be positive"; - fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } - if ( odds < 1 || odds > 9999 ) + if ( odds < 2 || odds > 9999 ) { - CCerror = "odds must be between 1 and 9999"; - fprintf(stderr,"%s\n", CCerror.c_str() ); + CCerror = "odds must be between 2 and 9999"; return(""); } if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,sbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) { +<<<<<<< HEAD CCerror = "Diceinit error in bet, is your transaction confirmed?"; +======= + CCerror = "error in Diceinit"; +>>>>>>> 880fda004f9487b7ca227f54d2f733f3139d935e return(""); } if ( bet < minbet || bet > maxbet || odds > maxodds ) { CCerror = strprintf("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); - fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } +<<<<<<< HEAD int32_t entropytxs; if ( (funding= DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid,entropytxs)) >= 2*bet*odds+txfee && entropyval != 0 ) +======= + int32_t entropytxs=0,emptyvar=0; + funding = DicePlanFunds(entropyval,entropytxid,sbits,cp,dicepk,fundingtxid,entropytxs,false); + DicePlanFunds(entropyval2,entropytxid2,sbits,cp,dicepk,fundingtxid,emptyvar,true); + if ( entropyval2 != 0 && entropytxid2 != zeroid ) { + entropyval = entropyval2; + entropytxid = entropytxid2; + } + if ( ( funding >= 2*bet*odds+txfee && entropyval != 0 ) ) +>>>>>>> 880fda004f9487b7ca227f54d2f733f3139d935e + { + if ( entropytxs < 100 ) { + CCerror = "Your dealer is broke, find a new casino."; + return(""); + } if ( myIsutxo_spentinmempool(entropytxid,0) != 0 ) { CCerror = "entropy txid is spent"; - fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } 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); + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1); mtx.vout.push_back(MakeCC1vout(cp->evalcode,entropyval,dicepk)); mtx.vout.push_back(MakeCC1vout(cp->evalcode,bet,dicepk)); 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 normal inputs for %.8f, plan funding %.8f\n",(double)bet/COIN,(double)funding/COIN); + } else CCerror = "cant find enough normal inputs for %.8f, plan funding %.8f\n"; } if ( entropyval == 0 && funding != 0 ) CCerror = "cant find dice entropy inputs"; else CCerror = "cant find dice input"; - fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } -std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout) +std::string DiceBetFinish(uint8_t &funcid,uint256 &entropyused,int32_t &entropyvout,int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettxid,int32_t winlosetimeout,uint256 vin0txid,int32_t vin0vout) { - 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=0,CCchange=0,odds,fundsneeded,minbet,maxbet,maxodds,timeoutblocks; uint8_t funcid=0; int32_t iswin=0; uint64_t entropyval,sbits; + CMutableTransaction mtx; CScript scriptPubKey,fundingPubKey; CTransaction oldbetTx,betTx,entropyTx; uint256 hentropyproof,entropytxid,hashBlock,bettorentropy,entropy,hentropy,oldbettxid; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int64_t inputs=0,CCchange=0,odds,fundsneeded,minbet,maxbet,maxodds,timeoutblocks; int32_t oldentropyvout,retval=0,iswin=0; uint64_t entropyval,sbits; + entropyused = zeroid; *resultp = 0; + funcid = 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 ) { @@ -997,7 +1492,7 @@ std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 return(""); } fundingpk = DiceFundingPk(fundingPubKey); - if ( winlosetimeout != 0 ) + if ( winlosetimeout != 0 ) // must be dealernode { scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG; if ( scriptPubKey != fundingPubKey ) @@ -1006,47 +1501,91 @@ std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 winlosetimeout = 0; } } - if ( AddNormalinputs(mtx,mypk,txfee,1) == 0 ) + if ( myGetTransaction(bettxid,betTx,hashBlock) != 0 && myGetTransaction(betTx.vin[0].prevout.hash,entropyTx,hashBlock) != 0 ) { - CCerror = "no txfee inputs for win/lose"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - return(""); - } - 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 ) + entropytxid = betTx.vin[0].prevout.hash; + /*if ( dice_betspent((char *)"DiceBetFinish",bettxid) != 0 ) { - if ( winlosetimeout != 0 ) - winlosetimeout = iswin; - if ( iswin == winlosetimeout ) + CCerror = "bettxid already spent"; + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + }*/ + bettorentropy = DiceGetEntropy(betTx,'B'); + if ( winlosetimeout == 0 || (iswin= DiceIsWinner(hentropyproof,entropyvout,bettxid,betTx,entropyTx,bettorentropy,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 ) + { + if ( vin0txid == zeroid || vin0vout < 0 ) { - if ( myIsutxo_spentinmempool(bettxid,0) != 0 || myIsutxo_spentinmempool(bettxid,1) != 0 ) + if ( AddNormalinputs(mtx,mypk,2*txfee,1) == 0 ) // must be a single vin!! { - CCerror = "bettxid already spent"; + CCerror = "no txfee inputs for win/lose"; fprintf(stderr,"%s\n", CCerror.c_str() ); return(""); } + } + else + { + //fprintf(stderr,"use vin0 %s/%d\n",vin0txid.GetHex().c_str(),vin0vout); + mtx.vin.push_back(CTxIn(vin0txid,vin0vout,CScript())); + } + if ( winlosetimeout != 0 ) // dealernode + { + entropyused = hentropyproof; + if ( vin0vout == -2 ) + retval = -1; + /*if ( iswin == 0 ) + { + retval = -1; + fprintf(stderr,"invalid dicebet %s\n",bettxid.GetHex().c_str()); + } else retval = 0;*/ + if ( retval < 0 || (retval= DiceEntropyUsed(oldbetTx,oldbettxid,oldentropyvout,entropyused,bettxid,betTx,entropyvout)) != 0 ) + { + if ( retval < 0 ) + { + fprintf(stderr,"orphan that reveals entropy, generate refund tx with proofs\n"); + // make sure we dont refund wrong amounts + mtx.vin.push_back(CTxIn(bettxid,0,CScript())); + mtx.vin.push_back(CTxIn(bettxid,1,CScript())); + funcid = 'R'; + mtx.vout.push_back(CTxOut(betTx.vout[0].nValue,fundingPubKey)); + mtx.vout.push_back(CTxOut(txfee,fundingPubKey)); + mtx.vout.push_back(CTxOut(betTx.vout[1].nValue,betTx.vout[2].scriptPubKey)); + *resultp = 1; + return(FinalizeCCTx(0,cp,mtx,fundingpk,txfee,EncodeDiceOpRet(funcid,sbits,fundingtxid,entropyused,oldbettxid))); // need to change opreturn to include oldbetTx to allow validation + } + else + { + CCerror = "DiceBetFinish: duplicate betTx"; + *resultp = -2; // demote error to warning + } + //fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } + //fprintf(stderr,"set winlosetimeout %d <- %d\n",winlosetimeout,iswin); + if ( (winlosetimeout= iswin) > 0 ) + funcid = 'W'; + else funcid = 'L'; + } + if ( iswin == winlosetimeout ) // dealernode and normal node paths should always get here + { //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 ) + if ( iswin == 0 && funcid != 'L' && funcid != 'W' ) // normal node path { - funcid = 'T'; if ( DiceVerifyTimeout(betTx,timeoutblocks) == 0 ) // hasnt timed out yet { return(""); } else { + funcid = 'T'; hentropy = hentropyproof = zeroid; iswin = 1; + fprintf(stderr,"set timeout win T\n"); } } - if ( iswin > 0 ) + if ( iswin > 0 && funcid != 0 ) // dealernode 'W' or normal node 'T' path { - if ( funcid != 'T' ) - funcid = 'W'; odds = (betTx.vout[2].nValue - txfee); if ( odds < 1 || odds > maxodds ) { @@ -1058,29 +1597,38 @@ std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 fundsneeded = txfee + (odds+1)*betTx.vout[1].nValue; if ( CCchange >= fundsneeded ) CCchange -= fundsneeded; - else if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60,sbits,fundingtxid)) > 0 ) + else if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,1,sbits,fundingtxid)) >= fundsneeded ) { if ( inputs > fundsneeded ) CCchange += (inputs - fundsneeded); } else { - CCerror = strprintf("not enough inputs for %.8f\n",(double)fundsneeded/COIN); - fprintf(stderr,"%s\n", CCerror.c_str() ); - return(""); + if ( (inputs= AddDiceInputs(cp,mtx,dicepk,fundsneeded,60,sbits,fundingtxid)) > 0 ) + { + if ( inputs > fundsneeded ) + CCchange += (inputs - fundsneeded); + } + else + { + CCerror = strprintf("not enough inputs for %.8f\n",(double)fundsneeded/COIN); + fprintf(stderr,"%s\n", CCerror.c_str() ); + return(""); + } } 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 + else // dealernode 'L' path { 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); + //fprintf(stderr,"make tx.%c\n",funcid); + if ( funcid == 'L' || funcid == 'W' ) // dealernode only + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1); *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)); @@ -1095,20 +1643,23 @@ std::string DiceBetFinish(int32_t *resultp,uint64_t txfee,char *planstr,uint256 } } *resultp = -1; - CCerror = "couldnt find bettx or entropytx"; - fprintf(stderr,"%s\n", CCerror.c_str() ); - return(""); + return("couldnt find bettx or entropytx"); } 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 ) + CScript fundingPubKey,scriptPubKey; CTransaction spenttx,betTx,entropyTx; uint256 hentropyproof,entropyused,hash,proof,txid,hashBlock,spenttxid,bettorentropy; CPubKey mypk,dicepk,fundingpk; struct CCcontract_info *cp,C; int32_t i,entropyvout,flag,win,loss,duplicate=0,result,iswin,vout,n=0; int64_t minbet,maxbet,maxodds,timeoutblocks,sum=0; uint64_t sbits,refsbits; char coinaddr[64]; std::string res; uint8_t funcid; + if ( (cp= Diceinit(fundingPubKey,fundingtxid,&C,planstr,txfee,mypk,dicepk,refsbits,minbet,maxbet,maxodds,timeoutblocks)) == 0 ) { +<<<<<<< HEAD CCerror = "Diceinit error in status, is your transaction confirmed?"; fprintf(stderr,"%s\n", CCerror.c_str() ); +======= + CCerror = "Diceinit error in status"; +>>>>>>> 880fda004f9487b7ca227f54d2f733f3139d935e return(0.); } + win = loss = 0; fundingpk = DiceFundingPk(fundingPubKey); scriptPubKey = CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG; GetCCaddress(cp,coinaddr,dicepk); @@ -1120,26 +1671,66 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx { txid = it->first.txhash; vout = (int32_t)it->first.index; - if ( GetTransaction(txid,betTx,hashBlock,false) != 0 && betTx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) + if ( vout != 0 ) + continue; + sum += it->second.satoshis; + if ( myGetTransaction(txid,betTx,hashBlock) != 0 && betTx.vout.size() >= 4 && betTx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) { - if ( DecodeDiceOpRet(txid,betTx.vout[betTx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof) == 'B' ) + if ( DecodeDiceOpRet(txid,betTx.vout[betTx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof) == 'B' && sbits == refsbits ) { - res = DiceBetFinish(&result,txfee,planstr,fundingtxid,txid,scriptPubKey == fundingPubKey); - if ( result > 0 ) + if ( myGetTransaction(betTx.vin[0].prevout.hash,entropyTx,hashBlock) != 0 ) { - mySendrawtransaction(res); - n++; - } + flag = 0; + if ( scriptPubKey == fundingPubKey ) + { + bettorentropy = DiceGetEntropy(betTx,'B'); + if ( (iswin= DiceIsWinner(hentropyproof,entropyvout,txid,betTx,entropyTx,bettorentropy,sbits,minbet,maxbet,maxodds,timeoutblocks,fundingtxid)) != 0 ) + { + if ( iswin > 0 ) + win++; + else if ( iswin < 0 ) + loss++; + n++; + DiceQueue(iswin,sbits,fundingtxid,txid,betTx,entropyvout); + } //else flag = 1; + } + if ( flag != 0 || scriptPubKey != fundingPubKey ) + { + if ( flag != 0 ) + fprintf(stderr,"illegal bettxid %d: iswin.%d W.%d L.%d %s/v%d (%c %.8f) %.8f\n",n,iswin,win,loss,txid.GetHex().c_str(),vout,funcid,(double)it->second.satoshis/COIN,(double)sum/COIN); + res = DiceBetFinish(funcid,entropyused,entropyvout,&result,txfee,planstr,fundingtxid,txid,scriptPubKey == fundingPubKey,zeroid,-1); + if ( result > 0 ) + { + mySenddicetransaction(res,entropyused,entropyvout,txid,betTx,funcid,0); + n++; + } + } + } else fprintf(stderr,"bettxid.%s cant find entropyTx.%s\n",txid.GetHex().c_str(),betTx.vin[0].prevout.hash.GetHex().c_str()); } } } - if ( 0 && scriptPubKey == fundingPubKey ) + if ( scriptPubKey == fundingPubKey ) { - for (i=0; i<=n; i++) + CTransaction tx; uint64_t entropyval; uint256 entropytxid; int32_t entropytxs; + DicePlanFunds(entropyval,entropytxid,refsbits,cp,dicepk,fundingtxid,entropytxs,false); + if ( entropytxs < DICE_MINUTXOS ) { - res = DiceAddfunding(txfee,planstr,fundingtxid,COIN); - fprintf(stderr,"ENTROPY tx:\n"); - mySendrawtransaction(res); + for (i=0; i 64 && is_hexstr((char *)res.c_str(),0) > 64 ) + { + if ( DecodeHexTx(tx,res) != 0 ) + { + //LOCK(cs_main); + if ( myAddtomempool(tx) != 0 ) + { + fprintf(stderr,"ENTROPY %s: %d of %d\n",tx.GetHash().GetHex().c_str(),i,DICE_MINUTXOS - entropytxs); + RelayTransaction(tx); + } else break; + } else break; + } else break; + } } } return(n); @@ -1150,7 +1741,7 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx if ( (vout= myIsutxo_spent(spenttxid,bettxid,1)) >= 0 ) { //fprintf(stderr,"bettx is spent\n"); - if ( GetTransaction(bettxid,betTx,hashBlock,false) != 0 && GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() > 2 ) + if ( myGetTransaction(bettxid,betTx,hashBlock) != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 2 ) { //fprintf(stderr,"found spenttxid %s\n",uint256_str(str,spenttxid)); if ( betTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 || betTx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 || spenttx.vout[2].scriptPubKey != betTx.vout[2].scriptPubKey ) @@ -1158,29 +1749,27 @@ double DiceStatus(uint64_t txfee,char *planstr,uint256 fundingtxid,uint256 bettx else return((double)spenttx.vout[2].nValue/COIN); } CCerror = "couldnt find bettx or spenttx %s\n",uint256_str(str,spenttxid); - fprintf(stderr,"%s\n", CCerror.c_str()); return(-1.); } else if ( scriptPubKey == fundingPubKey ) - res = DiceBetFinish(&result,txfee,planstr,fundingtxid,bettxid,1); - else res = DiceBetFinish(&result,txfee,planstr,fundingtxid,bettxid,0); + res = DiceBetFinish(funcid,entropyused,entropyvout,&result,txfee,planstr,fundingtxid,bettxid,1,zeroid,-1); + else res = DiceBetFinish(funcid,entropyused,entropyvout,&result,txfee,planstr,fundingtxid,bettxid,0,zeroid,-1); if ( result > 0 ) { - mySendrawtransaction(res); + mySenddicetransaction(res,entropyused,entropyvout,bettxid,betTx,funcid,0); sleep(1); if ( (vout= myIsutxo_spent(spenttxid,bettxid,1)) >= 0 ) { - if ( GetTransaction(txid,betTx,hashBlock,false) != 0 && GetTransaction(spenttxid,spenttx,hashBlock,false) != 0 && spenttx.vout.size() >= 2 ) + if ( myGetTransaction(txid,betTx,hashBlock) != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) { - if ( betTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 || betTx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 || spenttx.vout[2].scriptPubKey != betTx.vout[2].scriptPubKey ) + if ( funcid == 'L' )//betTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 || betTx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 || spenttx.vout[2].scriptPubKey != betTx.vout[2].scriptPubKey ) //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.); } CCerror = "didnt find dicefinish tx"; - fprintf(stderr,"%s\n", CCerror.c_str()); - } + } else CCerror = res; return(-1.); } return(0.); diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index d5d6b1c51..4fc855b46 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -76,11 +76,11 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) case EVAL_IMPORTPAYOUT: return ImportPayout(vparams, txTo, nIn); break; - + case EVAL_IMPORTCOIN: return ImportCoin(vparams, txTo, nIn); break; - + default: return(ProcessCC(cp,this, vparams, txTo, nIn)); break; @@ -98,10 +98,9 @@ bool Eval::GetSpendsConfirmed(uint256 hash, std::vector &spends) c bool Eval::GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const { - // 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); - return myGetTransaction(hash, txOut,hashBlock); + if (!myGetTransaction(hash, txOut,hashBlock)) { + return(GetTransaction(hash, txOut,hashBlock)); + } else return(true); } @@ -115,7 +114,6 @@ bool Eval::GetTxConfirmed(const uint256 &hash, CTransaction &txOut, CBlockIndex return true; } - unsigned int Eval::GetCurrentHeight() const { return chainActive.Height(); diff --git a/src/cc/eval.h b/src/cc/eval.h index b9189bc89..51752f0bc 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -47,7 +47,7 @@ EVAL(EVAL_FSM, 0xe7) \ EVAL(EVAL_AUCTION, 0xe8) \ EVAL(EVAL_LOTTO, 0xe9) \ - EVAL(EVAL_MOFN, 0xea) \ + EVAL(EVAL_HEIR, 0xea) \ EVAL(EVAL_CHANNELS, 0xeb) \ EVAL(EVAL_ORACLES, 0xec) \ EVAL(EVAL_PRICES, 0xed) \ diff --git a/src/cc/faucet.cpp b/src/cc/faucet.cpp index 676cb152c..3bf8a3476 100644 --- a/src/cc/faucet.cpp +++ b/src/cc/faucet.cpp @@ -142,14 +142,17 @@ bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) { - char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; + char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); + threshold = total/maxinputs; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; + if ( it->second.satoshis < threshold ) + continue; //char str[65]; fprintf(stderr,"check %s/v%d %.8f`\n",uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); // no need to prevent dup if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) diff --git a/src/cc/fsm.cpp b/src/cc/fsm.cpp index 41601b437..9f9accbb5 100644 --- a/src/cc/fsm.cpp +++ b/src/cc/fsm.cpp @@ -122,6 +122,7 @@ bool FSMValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) int64_t AddFSMInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) { + // add threshold check char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); diff --git a/src/cc/gateways.cpp b/src/cc/gateways.cpp index 1db08532a..a9fc6a4cd 100644 --- a/src/cc/gateways.cpp +++ b/src/cc/gateways.cpp @@ -143,7 +143,7 @@ */ -int32_t GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue) +void GatewaysAddQueue(std::string coin,uint256 txid,CScript scriptPubKey,int64_t nValue) { char destaddr[64],str[65]; Getscriptaddress(destaddr,scriptPubKey); @@ -178,6 +178,41 @@ uint8_t DecodeGatewaysOpRet(const CScript &scriptPubKey,std::string &coin,uint25 return(0); } +uint8_t DecodeGatewaysPartialOpRet(const CScript &scriptPubKey,int32_t &K, CPubKey &signerpk, std::string &coin,std::string &hex) +{ + 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 >> K; ss >> signerpk; ss >> coin; ss >> hex) != 0 ) + { + return(f); + } + return(0); +} + +uint8_t DecodeGatewaysWithdrawOpRet(const CScript &scriptPubKey, uint256 &assetid, std::string &refcoin, CPubKey &withdrawpub, int64_t &amount) +{ + 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 >> assetid; ss >> refcoin; ss >> withdrawpub; ss >> amount) != 0 ) + { + return(f); + } + return(0); +} +uint8_t DecodeGatewaysMarkdoneOpRet(const CScript &scriptPubKey, std::string &refcoin, uint256 &cointxid) +{ + 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 >> refcoin; ss >> cointxid) != 0 ) + { + return(f); + } + return(0); +} + uint8_t DecodeGatewaysBindOpRet(char *depositaddr,const CScript &scriptPubKey,std::string &coin,uint256 &tokenid,int64_t &totalsupply,uint256 &oracletxid,uint8_t &M,uint8_t &N,std::vector &pubkeys,uint8_t &taddr,uint8_t &prefix,uint8_t &prefix2) { std::vector vopret; uint8_t *script,e,f; @@ -297,15 +332,18 @@ bool GatewaysValidate(struct CCcontract_info *cp,Eval *eval,const CTransaction & int64_t AddGatewaysInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 refassetid,int64_t total,int32_t maxinputs) { - char coinaddr[64],destaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; + char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 assetid,txid,hashBlock; std::vector origpubkey; std::vector vopret; CTransaction vintx; int32_t j,vout,n = 0; uint8_t evalcode,funcid; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); + threshold = total/maxinputs; fprintf(stderr,"check %s for gateway inputs\n",coinaddr); for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; + if ( it->second.satoshis < threshold ) + continue; for (j=0; j withdrawpub,int64_t amount) +std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount) { - CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; + CMutableTransaction mtx; CTransaction tx; CPubKey mypk,gatewayspk; struct CCcontract_info *cp,C; + uint256 assetid,hashBlock,oracletxid; int32_t numvouts; int64_t totalsupply,inputs,CCchange=0; uint8_t M,N,taddr,prefix,prefix2; std::string coin; + std::vector msigpubkeys; char depositaddr[64],str[65],coinaddr[64]; CScript opret; cp = CCinit(&C,EVAL_GATEWAYS); if ( txfee == 0 ) txfee = 10000; @@ -788,11 +828,12 @@ std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin if ( inputs > amount ) CCchange = (inputs - amount); mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,amount,gatewayspk)); - mtx.vout.push_back(CTxOut(txfee,CScript() << withdrawpub << OP_CHECKSIG)); - mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG)); + mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(withdrawpub)) << OP_CHECKSIG)); + mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,txfee,gatewayspk)); if ( CCchange != 0 ) mtx.vout.push_back(MakeCC1vout(EVAL_GATEWAYS,CCchange,mypk)); - return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeAssetOpRet('t',assetid,zeroid,0,Mypubkey()))); + opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'W' << assetid << refcoin << withdrawpub << amount); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); } } fprintf(stderr,"cant find enough inputs or mismatched total\n"); @@ -806,6 +847,7 @@ std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string ref if ( txfee == 0 ) txfee = 5000; mypk = pubkey2pk(Mypubkey()); + mtx.vin.push_back(CTxIn(withdrawtxid,2,CScript())); mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'M' << cointxid << refcoin); @@ -814,8 +856,12 @@ std::string GatewaysMarkdone(uint64_t txfee,uint256 withdrawtxid,std::string ref UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) { - UniValue result(UniValue::VOBJ),pending(UniValue::VARR),obj(UniValue::VOBJ); CTransaction tx; std::string coin; CPubKey mypk,gatewayspk; std::vector msigpubkeys; uint256 hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],signeraddr[64]; int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply; struct CCcontract_info *cp,C; + UniValue result(UniValue::VOBJ),pending(UniValue::VARR); CTransaction tx; std::string coin,tmprefcoin; CPubKey mypk,gatewayspk,withdrawpub; std::vector msigpubkeys; + uint256 cointxid,hashBlock,assetid,txid,oracletxid; uint8_t M,N,taddr,prefix,prefix2; + char depositaddr[64],withmarker[64],coinaddr[64],destaddr[64],str[65],withaddr[64],numstr[32],txidaddr[64],signeraddr[64]; + int32_t i,n,numvouts,vout,numqueued,queueflag; int64_t totalsupply,amount,nValue; struct CCcontract_info *cp,C; std::vector > unspentOutputs; + cp = CCinit(&C,EVAL_GATEWAYS); mypk = pubkey2pk(Mypubkey()); gatewayspk = GetUnspendable(cp,0); @@ -837,20 +883,23 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) { queueflag = 1; break; - } - Getscriptaddress(withmarker,CScript() << ParseHex(HexStr(gatewayspk)) << OP_CHECKSIG); - SetCCunspents(unspentOutputs,withmarker); + } + SetCCunspents(unspentOutputs,coinaddr); numqueued = 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 ) + nValue = (int64_t)it->second.satoshis; + fprintf(stderr,"%s %d %ld\n",txid.ToString().c_str(),vout,(long)nValue); + if ( vout == 2 && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) && + DecodeGatewaysWithdrawOpRet(tx.vout[numvouts-1].scriptPubKey,assetid,tmprefcoin,withdrawpub,amount) == 'W' && myIsutxo_spentinmempool(txid,vout) == 0) { Getscriptaddress(destaddr,tx.vout[0].scriptPubKey); Getscriptaddress(withaddr,tx.vout[1].scriptPubKey); if ( strcmp(destaddr,coinaddr) == 0 ) { + UniValue obj(UniValue::VOBJ); obj.push_back(Pair("txid",uint256_str(str,txid))); CCtxidaddr(txidaddr,txid); obj.push_back(Pair("txidaddr",txidaddr)); @@ -873,31 +922,72 @@ UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin) return(result); } -std::string GatewaysMultisig(uint64_t txfee,std::string refcoin,uint256 bindtxid,uint256 withdrawtxid,char *txidaddr) +UniValue GatewaysMultisig(char *txidaddr) { - UniValue result(UniValue::VOBJ); std::string coin,hex; char str[67],numstr[65],depositaddr[64],gatewaysassets[64]; uint8_t M,N; std::vector pubkeys; uint8_t taddr,prefix,prefix2; uint256 tokenid,oracletxid,hashBlock; CTransaction tx; CPubKey Gatewayspk,mypk; struct CCcontract_info *cp,C; int32_t i,n,complete,partialtx; int64_t totalsupply; - cp = CCinit(&C,EVAL_GATEWAYS); - if ( txfee == 0 ) - txfee = 10000; - complete = partialtx = 0; - mypk = pubkey2pk(Mypubkey()); - Gatewayspk = GetUnspendable(cp,0); - _GetCCaddress(gatewaysassets,EVAL_GATEWAYS,Gatewayspk); - if ( GetTransaction(bindtxid,tx,hashBlock,false) != 0 ) + std::string parthex,hex,refcoin; uint256 txid,hashBlock; CTransaction tx; int32_t i,maxK,K,numvouts; CPubKey signerpk; + std::vector > unspentOutputs; UniValue result(UniValue::VOBJ); + + SetCCunspents(unspentOutputs,txidaddr); + maxK=0; + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { - depositaddr[0] = 0; - if ( tx.vout.size() > 0 && DecodeGatewaysBindOpRet(depositaddr,tx.vout[tx.vout.size()-1].scriptPubKey,coin,tokenid,totalsupply,oracletxid,M,N,pubkeys,taddr,prefix,prefix2) != 0 && M <= N && N > 1 && coin == refcoin ) + txid = it->first.txhash; + if (GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts=tx.vout.size()) > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) { - // need a decentralized way to add signatures to msig tx - n = pubkeys.size(); - for (i=0; i 0 && DecodeGatewaysPartialOpRet(txmempool.vout[numvouts-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK) + { + maxK=K; + parthex=hex; + } + } + + result.push_back(Pair("hex",parthex)); + result.push_back(Pair("number_of_signs",maxK)); + return (result); +} + +std::string GatewaysPartialSign(uint64_t txfee,uint256 txid,std::string refcoin, std::string hex) +{ + CMutableTransaction mtx; CScript opret; CPubKey mypk,txidaddrpk,signerpk; struct CCcontract_info *cp,C; CTransaction tx; + std::vector > unspentOutputs; char txidaddr[65]; + int32_t maxK,K=0; uint256 tmptxid,parttxid,hashBlock; + cp = CCinit(&C,EVAL_GATEWAYS); + if ( txfee == 0 ) + txfee = 5000; + mypk = pubkey2pk(Mypubkey()); + txidaddrpk=CCtxidaddr(txidaddr,txid); + SetCCunspents(unspentOutputs,txidaddr); + maxK=0; + if (unspentOutputs.size()==0) + { + if (AddNormalinputs(mtx,mypk,2*txfee,2)==0) fprintf(stderr,"error adding funds for partialsign\n"); + } + else + { + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + tmptxid = it->first.txhash; + if (GetTransaction(tmptxid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && DecodeGatewaysPartialOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,K,signerpk,refcoin,hex) == 'P' && K>maxK ) + { + maxK=K; + parttxid=tmptxid; + } + } + if (maxK>0) mtx.vin.push_back(CTxIn(parttxid,0,CScript())); + else fprintf(stderr,"Error finding previous partial tx\n"); + } + + mtx.vout.push_back(CTxOut(5000,CScript() << ParseHex(HexStr(txidaddrpk)) << OP_CHECKSIG)); + opret << OP_RETURN << E_MARSHAL(ss << cp->evalcode << 'P' << maxK+1 << mypk << refcoin << hex); + return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); } diff --git a/src/cc/MofN.cpp b/src/cc/heir.cpp similarity index 71% rename from src/cc/MofN.cpp rename to src/cc/heir.cpp index 84952176f..d4aab932a 100644 --- a/src/cc/MofN.cpp +++ b/src/cc/heir.cpp @@ -13,30 +13,15 @@ * * ******************************************************************************/ -#include "CCMofN.h" +#include "CCHeir.h" /* - The idea of MofN CC is to allow non-interactive multisig, preferably in a cross chain compatible way, ie. for actual bitcoin multisig. - - full redeemscript in an initial tx with opreturn - ability to post partial signatures and construct a full transaction from M such partial signatures - a new transaction would refer to the initialtx and other partial would refer to both - - There is no need for a CC contract to use it for normal multisig as normal multisig transactions are already supported. - - In order to take advantage of CC powers, we can create a more powerful multisig using shamir's secret MofN (up to 255) algo to allow spends. Using the same non-interactive partial signing is possible. also, in addition to spending, data payload can have additional data that is also revealed when the funds are spent. - - rpc calls needed: - 1) create msig address (normal or shamir) - 2) post payment with partial sig - 3) add partial sig to 2) - 4) combine and submit M partial sigs - + The idea of Heir CC is to allow crypto inheritance */ // start of consensus code -int64_t IsMofNvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) +int64_t IsHeirvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) { char destaddr[64]; if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 ) @@ -47,7 +32,7 @@ int64_t IsMofNvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v) return(0); } -bool MofNExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee) +bool HeirExactAmounts(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; int64_t inputs=0,outputs=0,assetoshis; @@ -65,8 +50,8 @@ bool MofNExactAmounts(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 MofN from mempool"); - if ( (assetoshis= IsMofNvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) + return eval->Invalid("cant Heir from mempool"); + if ( (assetoshis= IsHeirvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 ) inputs += assetoshis; } } @@ -74,7 +59,7 @@ bool MofNExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction & for (i=0; i origpubkey; CTransaction vintx; int32_t vout,n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); @@ -139,7 +125,7 @@ int64_t AddMofNInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe // no need to prevent dup if ( GetTransaction(txid,vintx,hashBlock,false) != 0 ) { - if ( (nValue= IsMofNvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 ) + if ( (nValue= IsHeirvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 ) { if ( total != 0 && maxinputs != 0 ) mtx.vin.push_back(CTxIn(txid,vout,CScript())); @@ -154,27 +140,27 @@ int64_t AddMofNInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe return(totalinputs); } -std::string MofNGet(uint64_t txfee,int64_t nValue) +std::string HeirGet(uint64_t txfee,int64_t nValue) { - CMutableTransaction mtx,tmpmtx; CPubKey mypk,mofnpk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; - cp = CCinit(&C,EVAL_MOFN); + CMutableTransaction mtx,tmpmtx; CPubKey mypk,Heirpk; int64_t inputs,CCchange=0; struct CCcontract_info *cp,C; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash; + cp = CCinit(&C,EVAL_HEIR); if ( txfee == 0 ) txfee = 10000; - mofnpk = GetUnspendable(cp,0); + Heirpk = GetUnspendable(cp,0); mypk = pubkey2pk(Mypubkey()); - if ( (inputs= AddMofNInputs(cp,mtx,mofnpk,nValue+txfee,60)) > 0 ) + if ( (inputs= AddHeirInputs(cp,mtx,Heirpk,nValue+txfee,60)) > 0 ) { if ( inputs > nValue ) CCchange = (inputs - nValue - txfee); if ( CCchange != 0 ) - mtx.vout.push_back(MakeCC1vout(EVAL_MOFN,CCchange,mofnpk)); + mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,CCchange,Heirpk)); mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); fprintf(stderr,"start at %u\n",(uint32_t)time(NULL)); j = rand() & 0xfffffff; for (i=0; i<1000000; i++,j++) { tmpmtx = mtx; - rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_MOFN << (uint8_t)'G' << j)); + rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'G' << j)); if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 ) { len >>= 1; @@ -190,35 +176,35 @@ std::string MofNGet(uint64_t txfee,int64_t nValue) } fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL)); return(""); - } else fprintf(stderr,"cant find mofn inputs\n"); + } else fprintf(stderr,"cant find Heir inputs\n"); return(""); } -std::string MofNFund(uint64_t txfee,int64_t funds) +std::string HeirFund(uint64_t txfee,int64_t funds) { - CMutableTransaction mtx; CPubKey mypk,mofnpk; CScript opret; struct CCcontract_info *cp,C; - cp = CCinit(&C,EVAL_MOFN); + CMutableTransaction mtx; CPubKey mypk,Heirpk; CScript opret; struct CCcontract_info *cp,C; + cp = CCinit(&C,EVAL_HEIR); if ( txfee == 0 ) txfee = 10000; mypk = pubkey2pk(Mypubkey()); - mofnpk = GetUnspendable(cp,0); + Heirpk = GetUnspendable(cp,0); if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 ) { - mtx.vout.push_back(MakeCC1vout(EVAL_MOFN,funds,mofnpk)); + mtx.vout.push_back(MakeCC1vout(EVAL_HEIR,funds,Heirpk)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret)); } return(""); } -UniValue MofNInfo() +UniValue HeirInfo() { UniValue result(UniValue::VOBJ); char numstr[64]; - CMutableTransaction mtx; CPubKey mofnpk; struct CCcontract_info *cp,C; int64_t funding; + CMutableTransaction mtx; CPubKey Heirpk; struct CCcontract_info *cp,C; int64_t funding; result.push_back(Pair("result","success")); - result.push_back(Pair("name","MofN")); - cp = CCinit(&C,EVAL_MOFN); - mofnpk = GetUnspendable(cp,0); - funding = AddMofNInputs(cp,mtx,mofnpk,0,0); + result.push_back(Pair("name","Heir")); + cp = CCinit(&C,EVAL_HEIR); + Heirpk = GetUnspendable(cp,0); + funding = AddHeirInputs(cp,mtx,Heirpk,0,0); sprintf(numstr,"%.8f",(double)funding/COIN); result.push_back(Pair("funding",numstr)); return(result); diff --git a/src/cc/lotto.cpp b/src/cc/lotto.cpp index 7129bfcd8..652ea9d0d 100644 --- a/src/cc/lotto.cpp +++ b/src/cc/lotto.cpp @@ -162,6 +162,7 @@ bool LottoValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) int64_t AddLottoInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) { + // add threshold check char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); @@ -291,10 +292,11 @@ std::string LottoCreate(uint64_t txfee,char *planstr,int64_t funding,int32_t tic sbits = stringbits(planstr); if ( AddNormalinputs(mtx,mypk,funding+txfee,60) > 0 ) { - hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash); + hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1); mtx.vout.push_back(MakeCC1vout(EVAL_LOTTO,funding,lottopk)); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_LOTTO << (uint8_t)'F' << sbits << ticketsize << odds << firstheight << period << hentropy))); } + return(""); } std::string LottoTicket(uint64_t txfee,uint256 lottoid,int64_t numtickets) diff --git a/src/cc/oracles.cpp b/src/cc/oracles.cpp index 0c7d9e6e2..8fe1fe6d3 100644 --- a/src/cc/oracles.cpp +++ b/src/cc/oracles.cpp @@ -440,6 +440,7 @@ int64_t correlate_price(int32_t height,int64_t *prices,int32_t n) for (i=0; i %llu ht.%d\n",(long long)price,height); + return(price); } int64_t OracleCorrelatedPrice(int32_t height,std::vector origprices) @@ -650,8 +651,12 @@ bool OraclesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t } return eval->Invalid("unexpected OraclesValidate 'D' tx invalid"); break; + default: + fprintf(stderr,"illegal oracles funcid.(%c)\n",script[1]); + return eval->Invalid("unexpected OraclesValidate funcid"); + break; } - } + } else return eval->Invalid("unexpected oracles missing funcid"); return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); } return(true); diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 6cd751b8d..f3cd40ba2 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -115,6 +115,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) { + // add threshold check char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); diff --git a/src/cc/pegs.cpp b/src/cc/pegs.cpp index d9074bd49..21e371b4a 100644 --- a/src/cc/pegs.cpp +++ b/src/cc/pegs.cpp @@ -122,6 +122,7 @@ bool PegsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) { + // add threshold check char coinaddr[64]; int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index 6ee0364e2..3d69ceec1 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -129,6 +129,7 @@ bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char *destaddr,uint256 tolenid,int64_t total,int32_t maxinputs) { + // add threshold check int64_t nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t vout,n = 0; std::vector > unspentOutputs; SetCCunspents(unspentOutputs,destaddr); diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index a70071af9..649a9a9e6 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -287,8 +287,12 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t return eval->Invalid("unlock tx vout.2 isnt 0"); preventCCvouts = 1; break; + default: + fprintf(stderr,"illegal rewards funcid.(%c)\n",funcid); + return eval->Invalid("unexpected rewards funcid"); + break; } - } + } else return eval->Invalid("unexpected rewards missing funcid"); return(PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts)); } return(true); @@ -325,15 +329,16 @@ static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t r // 'L' vs 'F' and 'A' int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs,uint64_t refsbits,uint256 reffundingtxid) { - char coinaddr[64],str[65]; uint64_t sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t numblocks,j,vout,n = 0; uint8_t funcid; + char coinaddr[64],str[65]; uint64_t threshold,sbits,nValue,totalinputs = 0; uint256 txid,hashBlock,fundingtxid; CTransaction tx; int32_t numblocks,j,vout,n = 0; uint8_t funcid; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); SetCCunspents(unspentOutputs,coinaddr); + threshold = total/maxinputs; for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) { txid = it->first.txhash; vout = (int32_t)it->first.index; - if ( it->second.satoshis < 1000000 ) + if ( it->second.satoshis < threshold ) continue; //fprintf(stderr,"(%s) %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); for (j=0; j origpubkey; CTransaction vintx; int32_t vout,n = 0; std::vector > unspentOutputs; GetCCaddress(cp,coinaddr,pk); diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp index c913c7ea0..1dd3fe706 100644 --- a/src/consensus/upgrades.cpp +++ b/src/consensus/upgrades.cpp @@ -69,6 +69,7 @@ int CurrentEpoch(int nHeight, const Consensus::Params& params) { return idxInt; } } + return(0); // jl777 seems the right value to return } uint32_t CurrentEpochBranchId(int nHeight, const Consensus::Params& params) { diff --git a/src/komodo.h b/src/komodo.h index 48d25d776..e6c9a8c54 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -113,7 +113,7 @@ int32_t komodo_parsestatefile(struct komodo_state *sp,FILE *fp,char *symbol,char errs++; if ( fread(&MoMdepth,1,sizeof(MoMdepth),fp) != sizeof(MoMdepth) ) errs++; - if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 ) + if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 ) printf("%s load[%s.%d -> %s] NOTARIZED %d %s MoM.%s %d CCid.%u\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str(),MoM.ToString().c_str(),MoMdepth&0xffff,(MoMdepth>>16)&0xffff); } else @@ -258,7 +258,7 @@ int32_t komodo_parsestatefiledata(struct komodo_state *sp,uint8_t *filedata,long errs++; if ( memread(&MoMdepth,sizeof(MoMdepth),filedata,&fpos,datalen) != sizeof(MoMdepth) ) errs++; - if ( 1 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 ) + if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && sp != 0 ) printf("%s load[%s.%d -> %s] NOTARIZED %d %s MoM.%s %d CCid.%u\n",ASSETCHAINS_SYMBOL,symbol,sp->NUM_NPOINTS,dest,notarized_height,notarized_hash.ToString().c_str(),MoM.ToString().c_str(),MoMdepth&0xffff,(MoMdepth>>16)&0xffff); } else diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index c19d5e664..5a4aedbb8 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1107,30 +1107,41 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ */ extern int32_t ASSETCHAINS_STREAM; -uint64_t komodo_commission(const CBlock *pblock) +CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams); + +uint64_t komodo_commission(const CBlock *pblock,int32_t height) { - int32_t i,j,n=0,txn_count; uint64_t commission,total = 0; + int32_t i,j,n=0,txn_count; int64_t nSubsidy; uint64_t commission,total = 0; + txn_count = pblock->vtx.size(); if ( ASSETCHAINS_STREAM == 0 ) { - txn_count = pblock->vtx.size(); - for (i=0; ivtx[i].vout.size(); - for (j=0; jvtx[i].vout[j].nValue; - } - } - //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN)); - commission = ((total * ASSETCHAINS_COMMISSION) / COIN); - if ( commission < 10000 ) - commission = 0; + if ( ASSETCHAINS_FOUNDERS != 0 ) + { + nSubsidy = GetBlockSubsidy(height,Params().GetConsensus()); + fprintf(stderr,"ht.%d nSubsidy %.8f prod %llu\n",height,(double)nSubsidy/COIN,(long long)(nSubsidy * ASSETCHAINS_COMMISSION)); + return((nSubsidy * ASSETCHAINS_COMMISSION) / COIN); + n = pblock->vtx[0].vout.size(); + for (j=0; jvtx[0].vout[j].nValue; + } + else + { + for (i=0; ivtx[i].vout.size(); + for (j=0; jvtx[i].vout[j].nValue; + } + } + } } else { - commission = 10000; + commission = 10000; } return(commission); } @@ -1172,7 +1183,7 @@ int8_t komodo_segid(int32_t nocache,int32_t height) return(segid); } -int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n) +void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n) { static uint8_t prevhashbuf[100]; static int32_t prevheight; int32_t i; @@ -1471,17 +1482,39 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_ int64_t komodo_checkcommission(CBlock *pblock,int32_t height) { - int64_t checktoshis=0; uint8_t *script; - if ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_STREAM != 0) + int64_t checktoshis=0; uint8_t *script,scripthex[8192]; int32_t scriptlen,matched = 0; + if ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_STREAM != 0 ) { - checktoshis = komodo_commission(pblock); - if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 ) + checktoshis = komodo_commission(pblock,height); + fprintf(stderr,"height.%d commission %.8f\n",height,(double)checktoshis/COIN); + /*if ( checktoshis > 10000 && pblock->vtx[0].vout.size() != 2 ) jl777: not sure why this was here return(-1); - else if ( checktoshis != 0 ) + else*/ if ( checktoshis != 0 ) { script = (uint8_t *)pblock->vtx[0].vout[1].scriptPubKey.data(); - if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 ) + scriptlen = (int32_t)pblock->vtx[0].vout[1].scriptPubKey.size(); + if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) + { + if ( ASSETCHAINS_SCRIPTPUB.size()/2 == scriptlen && scriptlen < sizeof(scripthex) ) + { + decode_hex(scripthex,scriptlen,(char *)ASSETCHAINS_SCRIPTPUB.c_str()); + if ( memcmp(scripthex,script,scriptlen) == 0 ) + matched = scriptlen; + } + } + else if ( scriptlen == 35 && script[0] == 33 && script[34] == OP_CHECKSIG && memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) == 0 ) + matched = 35; + else if ( scriptlen == 25 && script[0] == OP_DUP && script[1] == OP_HASH160 && script[2] == 20 && script[23] == OP_EQUALVERIFY && script[24] == OP_CHECKSIG && memcmp(script+3,ASSETCHAINS_OVERRIDE_PUBKEYHASH,20) == 0 ) + matched = 25; + if ( matched == 0 ) + { + int32_t i; + for (i=0; i<25; i++) + fprintf(stderr,"%02x",script[i]); + fprintf(stderr," payment to wrong pubkey scriptlen.%d, scriptpub[%d]\n",scriptlen,(int32_t)ASSETCHAINS_SCRIPTPUB.size()/2); return(-1); + + } if ( pblock->vtx[0].vout[1].nValue != checktoshis ) { fprintf(stderr,"ht.%d checktoshis %.8f vs actual vout[1] %.8f\n",height,dstr(checktoshis),dstr(pblock->vtx[0].vout[1].nValue)); diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 233f87fcf..593cb8b80 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1380,7 +1380,8 @@ void komodo_passport_iteration() } if ( komodo_chainactive_timestamp() > lastinterest ) { - komodo_interestsum(); + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + komodo_interestsum(); komodo_longestchain(); lastinterest = komodo_chainactive_timestamp(); } diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 1e42ded4a..9bb189683 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -46,19 +46,18 @@ int COINBASE_MATURITY = _COINBASE_MATURITY;//100; int32_t KOMODO_MININGTHREADS = -1,IS_KOMODO_NOTARY,IS_STAKED_NOTARY,ASSETCHAINS_STREAM,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAINS_SEED,KOMODO_ON_DEMAND,KOMODO_EXTERNAL_NOTARIES,KOMODO_PASSPORT_INITDONE,KOMODO_PAX,KOMODO_EXCHANGEWALLET,KOMODO_REWIND,STAKED_ERA,KOMODO_CONNECTING = -1; int32_t KOMODO_INSYNC,KOMODO_LASTMINED,prevKOMODO_LASTMINED,KOMODO_CCACTIVATE,JUMBLR_PAUSE = 1; - -std::string ASSETCHAINS_OVERRIDE_ADDRESS,NOTARY_ADDRESS,NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,WHITELIST_ADDRESS; -uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,NUM_NOTARIES; +std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY,DONATION_PUBKEY,ASSETCHAINS_SCRIPTPUB,NOTARY_ADDRESS,WHITELIST_ADDRESS; +uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEYHASH[20],ASSETCHAINS_PUBLIC,ASSETCHAINS_PRIVATE,ASSETCHAINS_TXPOW,NUM_NOTARIES,ASSETCHAINS_FOUNDERS; char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096],NOTARYADDRS[64][36]; uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; uint32_t ASSETCHAIN_INIT,ASSETCHAINS_CC,KOMODO_STOPAT,KOMODO_DPOWCONFS = 1; uint32_t ASSETCHAINS_MAGIC = 2387029918; uint64_t KOMODO_INTERESTSUM,KOMODO_WALLETBALANCE; -uint64_t ASSETCHAINS_FOUNDERS_REWARD,ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10,MIN_RECV_SATS; +uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10,MIN_RECV_SATS; uint32_t KOMODO_INITDONE; -char KMDUSERPASS[8192],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771; +char KMDUSERPASS[8192+512+1],BTCUSERPASS[8192]; uint16_t KMD_PORT = 7771,BITCOIND_RPCPORT = 7771; uint64_t PENDING_KOMODO_TX; extern int32_t KOMODO_LOADINGBLOCKS; unsigned int MAX_BLOCK_SIGOPS = 20000; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 962af99aa..be39b4d46 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1563,6 +1563,7 @@ void komodo_args(char *argv0) { MAX_BLOCK_SIGOPS = 60000; ASSETCHAINS_TXPOW = GetArg("-ac_txpow",0) & 3; + ASSETCHAINS_FOUNDERS = GetArg("-ac_founders",0) & 1; ASSETCHAINS_SUPPLY = GetArg("-ac_supply",10); ASSETCHAINS_ENDSUBSIDY = GetArg("-ac_end",0); ASSETCHAINS_REWARD = GetArg("-ac_reward",0); @@ -1570,8 +1571,7 @@ void komodo_args(char *argv0) ASSETCHAINS_DECAY = GetArg("-ac_decay",0); ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0); ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey",""); - ASSETCHAINS_FOUNDERS_REWARD = GetArg("-ac_freward",0); - ASSETCHAINS_OVERRIDE_ADDRESS = GetArg("-ac_address",""); + ASSETCHAINS_SCRIPTPUB = GetArg("-ac_script",""); ASSETCHAINS_STREAM = GetArg("-ac_stream",0); if ( ASSETCHAINS_STREAM != 0 && ( ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_PRIVATE != 0 )) { @@ -1600,21 +1600,38 @@ void komodo_args(char *argv0) ASSETCHAINS_DECAY = 0; printf("ASSETCHAINS_DECAY cant be more than 100000000\n"); } - if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 ) - decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str()); - else if ( ASSETCHAINS_COMMISSION != 0 ) + if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 || ASSETCHAINS_SCRIPTPUB.size() > 1 ) { - ASSETCHAINS_COMMISSION = 0; - printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); - } else if ( ASSETCHAINS_STREAM != 0) { - printf("ASSETCHAINS_STREAM needs ASSETCHAINS_OVERRIDE_PUBKEY! \n"); - exit(0); - } - if ( ASSETCHAINS_STREAM != 0 && ASSETCHAINS_SUPPLY == 10 ) { - ASSETCHAINS_SUPPLY = 1000000; - printf("ASSETCHAINS_STREAM is set with no supply, setting supply at 1,000,000 coins. \n"); - } - if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_STREAM != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 ) + if ( strlen(ASSETCHAINS_OVERRIDE_PUBKEY.c_str()) == 66 ) + { + decode_hex(ASSETCHAINS_OVERRIDE_PUBKEY33,33,(char *)ASSETCHAINS_OVERRIDE_PUBKEY.c_str()); + calc_rmd160_sha256(ASSETCHAINS_OVERRIDE_PUBKEYHASH,ASSETCHAINS_OVERRIDE_PUBKEY33,33); + } + else if ( ASSETCHAINS_STREAM != 0) + { + printf("ASSETCHAINS_STREAM needs ASSETCHAINS_OVERRIDE_PUBKEY! \n"); + exit(0); + } + if ( ASSETCHAINS_COMMISSION == 0 && ASSETCHAINS_FOUNDERS != 0 ) + { + ASSETCHAINS_COMMISSION = 53846154; // maps to 35% + printf("ASSETCHAINS_COMMISSION defaulted to 35%% when founders reward active\n"); + } + } + else + { + if ( ASSETCHAINS_COMMISSION != 0 ) + { + ASSETCHAINS_COMMISSION = 0; + printf("ASSETCHAINS_COMMISSION needs an ASETCHAINS_OVERRIDE_PUBKEY and cant be more than 100000000 (100%%)\n"); + } + if ( ASSETCHAINS_FOUNDERS != 0 ) + { + ASSETCHAINS_FOUNDERS = 0; + printf("ASSETCHAINS_FOUNDERS needs an ASETCHAINS_OVERRIDE_PUBKEY\n"); + } + } + if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 ) { fprintf(stderr,"end.%llu blocks, reward %.8f halving.%llu blocks, decay.%llu perc %.4f%% ac_pub=[%02x...]\n",(long long)ASSETCHAINS_ENDSUBSIDY,dstr(ASSETCHAINS_REWARD),(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0]); extraptr = extrabuf; @@ -1625,6 +1642,10 @@ void komodo_args(char *argv0) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY),(void *)&ASSETCHAINS_DECAY); val = ASSETCHAINS_COMMISSION | (((uint64_t)ASSETCHAINS_STAKED & 0xff) << 32) | (((uint64_t)ASSETCHAINS_CC & 0xffff) << 40) | ((ASSETCHAINS_PUBLIC != 0) << 7) | ((ASSETCHAINS_PRIVATE != 0) << 6) | ASSETCHAINS_TXPOW; extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val); + if ( ASSETCHAINS_FOUNDERS != 0 ) + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_FOUNDERS),(void *)&ASSETCHAINS_FOUNDERS); + if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) + extralen += iguana_rwnum(1,&extraptr[extralen],(int32_t)ASSETCHAINS_SCRIPTPUB.size(),(void *)ASSETCHAINS_SCRIPTPUB.c_str()); } addn = GetArg("-seednode",""); if ( strlen(addn.c_str()) > 0 ) @@ -1636,8 +1657,11 @@ void komodo_args(char *argv0) MAX_MONEY = (ASSETCHAINS_SUPPLY+100) * SATOSHIDEN; else MAX_MONEY = (ASSETCHAINS_SUPPLY+100) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY); MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSION) / SATOSHIDEN; - if ( ASSETCHAINS_CC >= KOMODO_FIRSTFUNGIBLEID && MAX_MONEY < 1000000LL*SATOSHIDEN ) + if ( ASSETCHAINS_CC >= KOMODO_FIRSTFUNGIBLEID && MAX_MONEY < 1000000LL*SATOSHIDEN ) MAX_MONEY = 1000000LL*SATOSHIDEN; + if ( MAX_MONEY <= 0 || MAX_MONEY > 1000000000LL*SATOSHIDEN ) + MAX_MONEY = 1000000000LL*SATOSHIDEN; + //fprintf(stderr,"MAX_MONEY %llu %.8f\n",(long long)MAX_MONEY,(double)MAX_MONEY/SATOSHIDEN); //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); ASSETCHAINS_P2PPORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 ) diff --git a/src/main.cpp b/src/main.cpp index 590e3569f..92634de0f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -95,6 +95,7 @@ unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA; CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE); CTxMemPool mempool(::minRelayTxFee); +CTxMemPool tmpmempool(::minRelayTxFee); struct COrphanTx { CTransaction tx; @@ -1365,7 +1366,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } auto verifier = libzcash::ProofVerifier::Strict(); - if ( komodo_validate_interest(tx,chainActive.LastTip()->nHeight+1,chainActive.LastTip()->GetMedianTimePast() + 777,0) < 0 ) + if ( ASSETCHAINS_SYMBOL[0] == 0 && komodo_validate_interest(tx,chainActive.LastTip()->nHeight+1,chainActive.LastTip()->GetMedianTimePast() + 777,0) < 0 ) { //fprintf(stderr,"AcceptToMemoryPool komodo_validate_interest failure\n"); return error("AcceptToMemoryPool: komodo_validate_interest failed"); @@ -1716,8 +1717,10 @@ bool myAddtomempool(CTransaction &tx) { CValidationState state; CTransaction Ltx; bool fMissingInputs,fOverrideFees = false; if ( mempool.lookup(tx.GetHash(),Ltx) == 0 ) + { + //fprintf(stderr,"call AcceptToMemoryPool\n"); return(AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)); - else return(true); + } else return(true); } bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) @@ -3181,7 +3184,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_STREAM != 0) ) { uint64_t checktoshis; - if ( (checktoshis= komodo_commission((CBlock *)&block)) != 0 ) + if ( (checktoshis= komodo_commission((CBlock *)&block,(int32_t)pindex->nHeight)) != 0 ) { if ( block.vtx[0].vout.size() == 2 && block.vtx[0].vout[1].nValue == checktoshis ) blockReward += checktoshis; @@ -3636,7 +3639,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * LogPrint("bench", " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001); LogPrint("bench", "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001); if ( KOMODO_LONGESTCHAIN != 0 && pindexNew->nHeight >= KOMODO_LONGESTCHAIN ) - KOMODO_INSYNC = 1; + KOMODO_INSYNC = (int32_t)pindexNew->nHeight; else KOMODO_INSYNC = 0; //fprintf(stderr,"connect.%d insync.%d\n",(int32_t)pindexNew->nHeight,KOMODO_INSYNC); if ( ASSETCHAINS_SYMBOL[0] == 0 && KOMODO_INSYNC != 0 ) @@ -4303,6 +4306,22 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C { CValidationState stateDummy; int32_t i,j,rejects=0,lastrejects=0; //fprintf(stderr,"put block's tx into mempool\n"); + // Copy all non Z-txs in mempool to temporary mempool because there can be tx in local mempool that make the block invalid. + LOCK(mempool.cs); + list transactionsToRemove; + BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx) { + const CTransaction &tx = e.GetTx(); + const uint256 &hash = tx.GetHash(); + if ( tx.vjoinsplit.size() == 0 ) { + transactionsToRemove.push_back(tx); + tmpmempool.addUnchecked(hash,e,!IsInitialBlockDownload()); + } + } + BOOST_FOREACH(const CTransaction& tx, transactionsToRemove) { + list removed; + mempool.remove(tx, removed, false); + } + // add all the txs in the block to the empty mempool. while ( 1 ) { for (i=0; i 0 ) + fprintf(stderr, "number of invalid txs: %d\n",invalidtxs ); + // empty the temp mempool for next time. + tmpmempool.clear(); + } return true; } @@ -4481,7 +4518,15 @@ bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidat if (ppindex) *ppindex = pindex; if ( pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK ) - return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); + { + if ( ASSETCHAINS_CC == 0 ) + return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); + else + { + fprintf(stderr,"reconsider block %s\n",hash.GetHex().c_str()); + pindex->nStatus &= ~BLOCK_FAILED_MASK; + } + } /*if ( pindex != 0 && hash == komodo_requestedhash ) { fprintf(stderr,"AddToBlockIndex A komodo_requestedhash %s\n",komodo_requestedhash.ToString().c_str()); diff --git a/src/miner.cpp b/src/miner.cpp index c2b95178e..f471b0013 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -109,7 +109,7 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,ASSETCHAINS_STREAM,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE; extern uint64_t ASSETCHAINS_REWARD,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],NOTARYADDRS[64][36]; -extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY; +extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB; void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len); extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],NUM_NOTARIES; @@ -119,7 +119,7 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33, int32_t komodo_pax_opreturn(int32_t height,uint8_t *opret,int32_t maxsize); int32_t komodo_baseid(char *origbase); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); -uint64_t komodo_commission(const CBlock *block); +uint64_t komodo_commission(const CBlock *block,int32_t height); int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33); @@ -355,6 +355,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount) //fprintf(stderr,"dont have inputs\n"); continue; } + if ( 0 ) { CValidationState state; auto verifier = libzcash::ProofVerifier::Disabled(); @@ -457,18 +458,23 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn,int32_t gpucount) txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; pblock->vtx[0] = txNew; - if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_STREAM != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block)) != 0 ) + if ( nHeight > 1 && ASSETCHAINS_SYMBOL[0] != 0 && (ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1) && (ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_STREAM != 0) && (commission= komodo_commission((CBlock*)&pblocktemplate->block)) != 0 ) { int32_t i; uint8_t *ptr; txNew.vout.resize(2); txNew.vout[1].nValue = commission; - txNew.vout[1].scriptPubKey.resize(35); - ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); - ptr[0] = 33; - for (i=0; i<33; i++) - ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; - ptr[34] = OP_CHECKSIG; - //printf("autocreate commission vout\n"); + if ( ASSETCHAINS_SCRIPTPUB.size() > 1 ) + txNew.vout[1].scriptPubKey = CScript() << ParseHex(ASSETCHAINS_SCRIPTPUB); + else + { + txNew.vout[1].scriptPubKey.resize(35); + ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); + ptr[0] = 33; + for (i=0; i<33; i++) + ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; + ptr[34] = OP_CHECKSIG; + } + //printf("autocreate commision vout\n"); pblock->vtx[0] = txNew; } pblocktemplate->vTxFees[0] = -nFees; @@ -794,7 +800,7 @@ void static BitcoinMiner() unsigned int n = chainparams.EquihashN(); unsigned int k = chainparams.EquihashK(); - uint8_t *script; uint64_t total,checktoshis; int32_t i,j,gpucount=KOMODO_MAXGPUCOUNT,notaryid = -1; + uint8_t *script; uint64_t total; int32_t i,j,gpucount=KOMODO_MAXGPUCOUNT,notaryid = -1; while ( (ASSETCHAIN_INIT == 0 || KOMODO_INITDONE == 0) ) { sleep(1); @@ -990,7 +996,7 @@ void static BitcoinMiner() { fprintf(stderr,"Mining when blockchain might not be in sync longest.%d vs %d\n",KOMODO_LONGESTCHAIN,Mining_height); if ( KOMODO_LONGESTCHAIN != 0 && Mining_height >= KOMODO_LONGESTCHAIN ) - KOMODO_INSYNC = 1; + KOMODO_INSYNC = Mining_height; sleep(3); } // Hash state diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 018e980f4..0893e9d03 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -590,6 +590,18 @@ bool myIsutxo_spentinmempool(uint256 txid,int32_t vout) return(false); } +bool mytxid_inmempool(uint256 txid) +{ + BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) + { + const CTransaction &tx = e.GetTx(); + const uint256 &hash = tx.GetHash(); + if ( txid == hash ) + return(true); + } + return(false); +} + UniValue mempoolToJSON(bool fVerbose = false) { if (fVerbose) diff --git a/src/rpccrosschain.cpp b/src/rpccrosschain.cpp index 26edb575a..b5aa7b7a7 100644 --- a/src/rpccrosschain.cpp +++ b/src/rpccrosschain.cpp @@ -50,7 +50,9 @@ UniValue assetchainproof(const UniValue& params, bool fHelp) UniValue crosschainproof(const UniValue& params, bool fHelp) { - + UniValue ret(UniValue::VOBJ); + //fprintf(stderr,"crosschainproof needs to be implemented\n"); + return(ret); } diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index af4eb0ee2..e51a50a97 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -124,9 +124,15 @@ UniValue getinfo(const UniValue& params, bool fHelp) #ifdef ENABLE_WALLET if (pwalletMain) { obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); - obj.push_back(Pair("balance", ValueFromAmount(KOMODO_WALLETBALANCE))); //pwalletMain->GetBalance() if ( ASSETCHAINS_SYMBOL[0] == 0 ) - obj.push_back(Pair("interest", ValueFromAmount(KOMODO_INTERESTSUM))); //komodo_interestsum() + { + obj.push_back(Pair("interest", ValueFromAmount(KOMODO_INTERESTSUM))); + obj.push_back(Pair("balance", ValueFromAmount(KOMODO_WALLETBALANCE))); //pwalletMain->GetBalance() + } + else + { + obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); // + } } #endif //fprintf(stderr,"after wallet %u\n",(uint32_t)time(NULL)); @@ -168,13 +174,13 @@ UniValue getinfo(const UniValue& params, bool fHelp) if ( ASSETCHAINS_CC != 0 ) obj.push_back(Pair("CCid", (int)ASSETCHAINS_CC)); obj.push_back(Pair("name", ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL)); + obj.push_back(Pair("p2pport", ASSETCHAINS_P2PPORT)); + obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT)); if ( ASSETCHAINS_SYMBOL[0] != 0 ) { if ( is_STAKED(ASSETCHAINS_SYMBOL) != 0 ) obj.push_back(Pair("StakedEra", STAKED_ERA)); //obj.push_back(Pair("name", ASSETCHAINS_SYMBOL)); - obj.push_back(Pair("p2pport", ASSETCHAINS_P2PPORT)); - obj.push_back(Pair("rpcport", ASSETCHAINS_RPCPORT)); obj.push_back(Pair("magic", (int)ASSETCHAINS_MAGIC)); if ( ASSETCHAINS_SUPPLY != 0 ) obj.push_back(Pair("premine", ASSETCHAINS_SUPPLY)); diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp index db6ffbc14..97bf5001d 100644 --- a/src/rpcnet.cpp +++ b/src/rpcnet.cpp @@ -179,6 +179,8 @@ int32_t komodo_longestchain() //fprintf(stderr,"komodo_longestchain iter.%d\n",n); CNodeStateStats statestats; bool fStateStats = GetNodeStateStats(stats.nodeid,statestats); + if ( statestats.nSyncHeight < 0 ) + continue; ht = 0; if ( stats.nStartingHeight > ht ) ht = stats.nStartingHeight; @@ -190,7 +192,6 @@ int32_t komodo_longestchain() maxheight = ht, num = 1; else if ( ht > maxheight*0.99 ) num++; - n++; if ( ht > height ) height = ht; } diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c9d4afe09..7267461b3 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -242,7 +242,7 @@ extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; UniValue stop(const UniValue& params, bool fHelp) { - char buf[64]; + char buf[66+128]; // Accept the deprecated and ignored 'detach' boolean argument if (fHelp || params.size() > 1) throw runtime_error( @@ -376,8 +376,8 @@ static const CRPCCommand vRPCCommands[] = { "faucet", "faucetget", &faucetget, true }, { "faucet", "faucetaddress", &faucetaddress, true }, - /* MofN */ - { "MofN", "mofnaddress", &mofnaddress, true }, + /* Heir */ + { "heir", "heiraddress", &heiraddress, true }, /* Channels */ { "channels", "channelsaddress", &channelsaddress, true }, @@ -427,6 +427,7 @@ static const CRPCCommand vRPCCommands[] = { "gateways", "gatewayspending", &gatewayspending, true }, { "gateways", "gatewaysmultisig", &gatewaysmultisig, true }, { "gateways", "gatewaysmarkdone", &gatewaysmarkdone, true }, + { "gateways", "gatewayspartialsign", &gatewayspartialsign, true }, /* dice */ { "dice", "dicelist", &dicelist, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index b2ec18bc0..873e2dc05 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -222,7 +222,7 @@ extern UniValue tokenask(const UniValue& params, bool fHelp); extern UniValue tokencancelask(const UniValue& params, bool fHelp); extern UniValue tokenfillask(const UniValue& params, bool fHelp); extern UniValue tokenconvert(const UniValue& params, bool fHelp); -extern UniValue mofnaddress(const UniValue& params, bool fHelp); +extern UniValue heiraddress(const UniValue& params, bool fHelp); extern UniValue channelsaddress(const UniValue& params, bool fHelp); extern UniValue oraclesaddress(const UniValue& params, bool fHelp); extern UniValue oracleslist(const UniValue& params, bool fHelp); @@ -253,6 +253,7 @@ extern UniValue gatewayswithdraw(const UniValue& params, bool fHelp); extern UniValue gatewayspending(const UniValue& params, bool fHelp); extern UniValue gatewaysmarkdone(const UniValue& params, bool fHelp); extern UniValue gatewaysmultisig(const UniValue& params, bool fHelp); +extern UniValue gatewayspartialsign(const UniValue& params, bool fHelp); extern UniValue channelsinfo(const UniValue& params, bool fHelp); extern UniValue channelsopen(const UniValue& params, bool fHelp); extern UniValue channelspayment(const UniValue& params, bool fHelp); diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 9aa02bfb7..c6e1e50b0 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -246,7 +246,7 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) CPubKey pubKey(vSolutions[0]); if (!pubKey.IsValid()) { - fprintf(stderr,"TX_PUBKEY invalid pubkey\n"); + //fprintf(stderr,"TX_PUBKEY invalid pubkey\n"); return false; } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 873cc5594..05cbb5dee 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -51,6 +51,7 @@ extern UniValue TxJoinSplitToJSON(const CTransaction& tx); extern uint8_t ASSETCHAINS_PRIVATE; uint32_t komodo_segid32(char *coinaddr); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); +int32_t komodo_isnotaryvout(char *coinaddr); // from ac_private chains only int64_t nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -2887,7 +2888,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) uint64_t komodo_interestsum() { #ifdef ENABLE_WALLET - if ( GetBoolArg("-disablewallet", false) == 0 ) + if ( ASSETCHAINS_SYMBOL[0] == 0 && GetBoolArg("-disablewallet", false) == 0 ) { uint64_t interest,sum = 0; int32_t txheight; uint32_t locktime; vector vecOutputs; @@ -3559,6 +3560,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) " \"txid\": xxxxx, (string) the transaction id\n" " \"amount\": xxxxx, (numeric) the amount of value in the note\n" " \"memo\": xxxxx, (string) hexademical string representation of memo field\n" + " \"jsindex\": xxxxx, (numeric) the JoinSplit index\n" "}\n" "\nExamples:\n" + HelpExampleCli("z_listreceivedbyaddress", "\"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") @@ -3600,6 +3602,7 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp) obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.plaintext.value)))); std::string data(entry.plaintext.memo.begin(), entry.plaintext.memo.end()); obj.push_back(Pair("memo", HexStr(data))); + obj.push_back(Pair("jsindex", entry.jsop.js)); result.push_back(obj); } return result; @@ -3937,7 +3940,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp) throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address ); } } - else if ( ASSETCHAINS_PRIVATE != 0 ) + else if ( ASSETCHAINS_PRIVATE != 0 && komodo_isnotaryvout((char *)address.c_str()) == 0 ) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "cant use transparent addresses in private chain"); if (setAddress.count(address)) @@ -4692,7 +4695,7 @@ int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr); int8_t komodo_stakehash(uint256 *hashp,char *address,uint8_t *hashbuf,uint256 txid,int32_t vout); -int32_t komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n); +void komodo_segids(uint8_t *hashbuf,int32_t height,int32_t n); int32_t komodo_notaryvin(CMutableTransaction &txNew,uint8_t *notarypub33) { @@ -5262,17 +5265,17 @@ UniValue gatewaysaddress(const UniValue& params, bool fHelp) return(CCaddress(cp,(char *)"Gateways",pubkey)); } -UniValue mofnaddress(const UniValue& params, bool fHelp) +UniValue heiraddress(const UniValue& params, bool fHelp) { struct CCcontract_info *cp,C; std::vector pubkey; - cp = CCinit(&C,EVAL_MOFN); + cp = CCinit(&C,EVAL_HEIR); if ( fHelp || params.size() > 1 ) - throw runtime_error("mofnaddress [pubkey]\n"); + throw runtime_error("heiraddress [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 *)"MofN",pubkey)); + return(CCaddress(cp,(char *)"Heir",pubkey)); } UniValue lottoaddress(const UniValue& params, bool fHelp) @@ -5790,7 +5793,7 @@ UniValue gatewayswithdraw(const UniValue& params, bool fHelp) coin = params[1].get_str(); withdrawpub = ParseHex(params[2].get_str()); amount = atof((char *)params[3].get_str().c_str()) * COIN; - hex = GatewaysWithdraw(0,bindtxid,coin,withdrawpub,amount); + hex = GatewaysWithdraw(0,bindtxid,coin,pubkey2pk(withdrawpub),amount); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); @@ -5834,18 +5837,30 @@ UniValue gatewayspending(const UniValue& params, bool fHelp) UniValue gatewaysmultisig(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); uint256 bindtxid,withtxid; std::string coin,hex; char *txidaddr; - if ( fHelp || params.size() != 2 ) - throw runtime_error("gatewaysmultisig bindtxid coin withtxid txidaddr\n"); + UniValue result(UniValue::VOBJ); std::string hex; char *txidaddr; + if ( fHelp || params.size() != 1 ) + throw runtime_error("gatewaysmultisig txidaddr\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); - bindtxid = Parseuint256((char *)params[0].get_str().c_str()); + txidaddr = (char *)params[0].get_str().c_str(); + return(GatewaysMultisig(txidaddr)); +} + +UniValue gatewayspartialsign(const UniValue& params, bool fHelp) +{ + UniValue result(UniValue::VOBJ); std::string coin,parthex,hex; uint256 txid; + if ( fHelp || params.size() != 3 ) + throw runtime_error("gatewayspartialsign txidaddr refcoin hex\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); + txid = Parseuint256((char *)params[0].get_str().c_str()); coin = params[1].get_str(); - withtxid = Parseuint256((char *)params[2].get_str().c_str()); - txidaddr = (char *)params[3].get_str().c_str(); - hex = GatewaysMultisig(0,coin,bindtxid,withtxid,txidaddr); + parthex = params[2].get_str(); + hex = GatewaysPartialSign(0,txid,coin,parthex); if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); @@ -5884,7 +5899,8 @@ UniValue oraclesregister(const UniValue& params, bool fHelp) const CKeyStore& keystore = *pwalletMain; LOCK2(cs_main, pwalletMain->cs_wallet); txid = Parseuint256((char *)params[0].get_str().c_str()); - datafee = atol((char *)params[1].get_str().c_str()); + if ( (datafee= atol((char *)params[1].get_str().c_str())) == 0 ) + datafee = atof((char *)params[1].get_str().c_str()) * COIN; hex = OracleRegister(0,txid,datafee); if ( hex.size() > 0 ) { @@ -6304,7 +6320,7 @@ UniValue diceaddfunds(const UniValue& params, bool fHelp) UniValue dicebet(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid; int64_t amount,odds; char *name; + UniValue result(UniValue::VOBJ); std::string hex,error; uint256 fundingtxid; int64_t amount,odds; char *name; if ( fHelp || params.size() != 4 ) throw runtime_error("dicebet name fundingtxid amount odds\n"); if ( ensure_CCrequirements() < 0 ) @@ -6322,14 +6338,12 @@ UniValue dicebet(const UniValue& params, bool fHelp) } if (amount > 0 && odds > 0) { hex = DiceBet(0,name,fundingtxid,amount,odds); - if ( CCerror != "" ) - { - ERR_RESULT(CCerror); - } else if ( hex.size() > 0 ) + RETURN_IF_ERROR(CCerror); + if ( hex.size() > 0 ) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); - } else ERR_RESULT("couldnt create dice bet transaction. make sure your address has funds"); + } } else { ERR_RESULT("amount and odds must be positive"); } @@ -6338,7 +6352,7 @@ UniValue dicebet(const UniValue& params, bool fHelp) UniValue dicefinish(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string hex; int32_t r; + UniValue result(UniValue::VOBJ); uint8_t funcid; char *name; uint256 entropyused,fundingtxid,bettxid; std::string hex; int32_t r,entropyvout; if ( fHelp || params.size() != 3 ) throw runtime_error("dicefinish name fundingtxid bettxid\n"); if ( ensure_CCrequirements() < 0 ) @@ -6352,7 +6366,7 @@ UniValue dicefinish(const UniValue& params, bool fHelp) } 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); + hex = DiceBetFinish(funcid,entropyused,entropyvout,&r,0,name,fundingtxid,bettxid,1,zeroid,-1); if ( CCerror != "" ) { ERR_RESULT(CCerror); @@ -6360,13 +6374,20 @@ UniValue dicefinish(const UniValue& params, bool fHelp) { result.push_back(Pair("result", "success")); result.push_back(Pair("hex", hex)); + if ( funcid != 0 ) + { + char funcidstr[2]; + funcidstr[0] = funcid; + funcidstr[1] = 0; + result.push_back(Pair("funcid", funcidstr)); + } } else ERR_RESULT( "couldnt create dicefinish transaction"); return(result); } UniValue dicestatus(const UniValue& params, bool fHelp) { - UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string status; double winnings; + UniValue result(UniValue::VOBJ); char *name; uint256 fundingtxid,bettxid; std::string status,error; double winnings; if ( fHelp || (params.size() != 2 && params.size() != 3) ) throw runtime_error("dicestatus name fundingtxid bettxid\n"); if ( ensure_CCrequirements() < 0 ) @@ -6383,10 +6404,8 @@ UniValue dicestatus(const UniValue& params, bool fHelp) if ( params.size() == 3 ) bettxid = Parseuint256((char *)params[2].get_str().c_str()); winnings = DiceStatus(0,name,fundingtxid,bettxid); - if (CCerror != "") { - ERR_RESULT(CCerror); - return result; - } + RETURN_IF_ERROR(CCerror); + result.push_back(Pair("result", "success")); if ( winnings >= 0. ) { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 70df32bef..67b81ea77 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1208,4 +1208,6 @@ public: /** Error status printout */ #define ERR_RESULT(x) result.push_back(Pair("result", "error")) , result.push_back(Pair("error", x)); +#define RETURN_IF_ERROR(CCerror) if ( CCerror != "" ) { ERR_RESULT(CCerror); return(result); } + #endif // BITCOIN_WALLET_WALLET_H