diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index f5877c711..13d7236d4 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -195,6 +195,8 @@ int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, C int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid); bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx); +void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std::vector payload); +int32_t payments_parsehexdata(std::vector &hexdata,cJSON *item,int32_t len); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, vscript_t vopretNonfungible); CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector origpubkey, std::string name, std::string description, std::vector> oprets); diff --git a/src/cc/CCtx.cpp b/src/cc/CCtx.cpp index ed06c1a4d..2713dd9ed 100644 --- a/src/cc/CCtx.cpp +++ b/src/cc/CCtx.cpp @@ -601,7 +601,6 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3 return(0); } - int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs) { int32_t abovei,belowi,ind,vout,i,n = 0; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up; diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 1330c6b3e..65c706862 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -38,6 +38,9 @@ std::string MYCCLIBNAME = (char *)"rogue"; #elif BUILD_CUSTOMCC #include "customcc.h" +#elif BUILD_GAMESCC +#include "gamescc.h" + #else #define EVAL_SUDOKU 17 #define EVAL_MUSIG 18 @@ -45,6 +48,10 @@ std::string MYCCLIBNAME = (char *)"rogue"; std::string MYCCLIBNAME = (char *)"sudoku"; #endif +#ifndef BUILD_GAMESCC +void komodo_netevent(std::vector payload) {} +#endif + char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); } struct CClib_rpcinfo @@ -73,6 +80,8 @@ CClib_methods[] = { (char *)"rogue", (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, 'X', EVAL_ROGUE }, #elif BUILD_CUSTOMCC RPC_FUNCS +#elif BUILD_GAMESCC + RPC_FUNCS #else { (char *)"sudoku", (char *)"gen", (char *)"", 0, 0, 'G', EVAL_SUDOKU }, { (char *)"sudoku", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_SUDOKU }, @@ -222,6 +231,8 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr) } #elif BUILD_CUSTOMCC CUSTOM_DISPATCH +#elif BUILD_GAMESCC + CUSTOM_DISPATCH #else if ( cp->evalcode == EVAL_SUDOKU ) { @@ -420,6 +431,8 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C return(rogue_validate(cp,height,eval,tx)); #elif BUILD_CUSTOMCC return(custom_validate(cp,height,eval,tx)); +#elif BUILD_GAMESCC + return(games_validate(cp,height,eval,tx)); #else if ( cp->evalcode == EVAL_SUDOKU ) return(sudoku_validate(cp,height,eval,tx)); @@ -677,6 +690,9 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len) #elif BUILD_CUSTOMCC #include "customcc.cpp" +#elif BUILD_GAMESCC +#include "gamescc.cpp" + #else #include "sudoku.cpp" #include "musig.cpp" diff --git a/src/cc/gamescc.cpp b/src/cc/gamescc.cpp new file mode 100644 index 000000000..29df990b5 --- /dev/null +++ b/src/cc/gamescc.cpp @@ -0,0 +1,194 @@ + +/* +./c cclib rng 17 \"[%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,250]\" +{ + "playerid": 250, + "seed": 1398876319979341887, + "rng": 14565767519458298868, + "lastrng": 15075236803740723044, + "maxrngs": 10000, + "result": "success" +} + + ./c cclib rngnext 17 \"[14565767519458298868]\" + { + "seed": 14565767519458297856, + "rng": 4253087318999719449, + "result": "success" + } + + The idea is for a game to start with a near future blockhash, so the lobby gets players signed up until just prior to the designated height. then that blockhash can be used to create a stream of rngs. + + the same initial rng can be used for all players, if the identical starting condition is required. up to 255 different initial rng can be derived from a single blockhash. (Actually any number is possible, for simplicity rng rpc limits to 255). + + you will notice maxrngs and lastrng, the lastrng is the rng value that will happen after maxrng iterations of calling rngnext with the current rng. This allows making time based multiplayer games where all the nodes can validate all the other nodes rng, even without realtime synchronization of all user input events. + + Every time period, all players would set their rng value to the lastrng value. The only thing to be careful of is it not exceed the maxrng calls to rngnext in a single time period. otherwise the same set of rng numbers will be repeated. +*/ + + +CScript games_opret(uint8_t funcid,CPubKey pk) +{ + CScript opret; uint8_t evalcode = EVAL_GAMES; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk); + return(opret); +} + +uint8_t games_opretdecode(CPubKey &pk,CScript scriptPubKey) +{ + std::vector vopret; uint8_t e,f; + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_GAMES ) + { + return(f); + } + return(0); +} + +UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag) +{ + CTransaction tx; + if ( rawtx.size() > 0 ) + { + result.push_back(Pair("hex",rawtx)); + if ( DecodeHexTx(tx,rawtx) != 0 ) + { + if ( broadcastflag != 0 && myAddtomempool(tx) != 0 ) + RelayTransaction(tx); + result.push_back(Pair("txid",tx.GetHash().ToString())); + result.push_back(Pair("result","success")); + } else result.push_back(Pair("error","decode hex")); + } else result.push_back(Pair("error","couldnt finalize CCtx")); + return(result); +} + +uint64_t _games_rngnext(uint64_t initseed) +{ + uint16_t seeds[4]; int32_t i; + seeds[0] = initseed; + seeds[1] = (initseed >> 16); + seeds[2] = (initseed >> 32); + seeds[3] = (initseed >> 48); + seeds[0] = (seeds[0]*GAMES_RNGMULT + GAMES_RNGOFFSET); + seeds[1] = ((seeds[0] ^ seeds[1])*GAMES_RNGMULT + GAMES_RNGOFFSET); + seeds[2] = ((seeds[0] ^ seeds[1] ^ seeds[2])*GAMES_RNGMULT + GAMES_RNGOFFSET); + seeds[3] = ((seeds[0] ^ seeds[1] ^ seeds[2] ^ seeds[3])*GAMES_RNGMULT + GAMES_RNGOFFSET); + return(((uint64_t)seeds[3] << 48) | ((uint64_t)seeds[2] << 24) | ((uint64_t)seeds[1] << 16) | seeds[0]); +} + +UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); int32_t n; uint64_t seed; + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) + { + seed = jdouble(jitem(params,0),0); + result.push_back(Pair("seed",seed)); + seed = _games_rngnext(seed); + result.push_back(Pair("rng",seed)); + result.push_back(Pair("result","success")); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough params")); + } + return(result); +} + +UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); int32_t i,n,playerid=0; uint64_t seed=0,initseed; bits256 hash; + if ( params != 0 && ((n= cJSON_GetArraySize(params)) == 1 || n == 2) ) + { + hash = jbits256(jitem(params,0),0); + if ( n == 2 ) + { + playerid = juint(jitem(params,1),0); + if ( playerid >= 0xff ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","playerid too big")); + return(result); + } + } + playerid++; + for (i=0; i<8; i++) + { + if ( ((1 << i) & playerid) != 0 ) + seed ^= (uint64_t)hash.uints[i] << ((i&1)*32); + } + initseed = seed; + seed = _games_rngnext(initseed); + result.push_back(Pair("playerid",(int64_t)(playerid - 1))); + result.push_back(Pair("seed",initseed)); + result.push_back(Pair("rng",seed)); + for (i=0; i payload; int32_t n; + if ( params != 0 && (n= cJSON_GetArraySize(params)) == 1 ) + { + if ( payments_parsehexdata(payload,jitem(params,0),0) == 0 ) + { + komodo_sendmessage(4,8,"events",payload); + result.push_back(Pair("result","success")); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parsehexdata")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough params")); + } + return(result); +} + +UniValue games_create(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + return(result); +} + +UniValue games_info(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + return(result); +} + +UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + return(result); +} + +void komodo_netevent(std::vector payload) +{ + int32_t i; + for (i=0; ievalcode == EVAL_GAMES ) \ +{ \ + if ( strcmp(method,"rng") == 0 ) \ + return(games_rng(txfee,cp,params)); \ + else if ( strcmp(method,"rngnext") == 0 ) \ + return(games_rngnext(txfee,cp,params)); \ + else if ( strcmp(method,"create") == 0 ) \ + return(games_create(txfee,cp,params)); \ + else if ( strcmp(method,"info") == 0 ) \ + return(games_info(txfee,cp,params)); \ + else if ( strcmp(method,"register") == 0 ) \ + return(games_register(txfee,cp,params)); \ + else if ( strcmp(method,"events") == 0 ) \ + return(games_events(txfee,cp,params)); \ + else \ + { \ + result.push_back(Pair("result","error")); \ + result.push_back(Pair("error","invalid gamescc method")); \ + result.push_back(Pair("method",method)); \ + return(result); \ + } \ +} diff --git a/src/cc/makegames b/src/cc/makegames new file mode 100755 index 000000000..b4b8cb803 --- /dev/null +++ b/src/cc/makegames @@ -0,0 +1,7 @@ +#!/bin/sh +gcc -O3 -DBUILD_GAMESCC -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o gamescc.so cclib.cpp +cp gamescc.so ../libcc.so +cd .. +make +cd cc + diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index d63f23515..6bd575835 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -310,7 +310,7 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) { int32_t latestheight,nextheight = komodo_nextheight(); CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); UniValue result(UniValue::VOBJ); uint256 createtxid,hashBlock; - CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease,totalallocations,checkallocations=0,allocation; int64_t inputsum,amount,CCchange=0; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector txidoprets; + CTransaction tx,txO; CPubKey mypk,txidpk,Paymentspk; int32_t i,n,m,numoprets=0,lockedblocks,minrelease,totalallocations,checkallocations=0,allocation; int64_t newamount,inputsum,amount,CCchange=0; CTxOut vout; CScript onlyopret; char txidaddr[64],destaddr[64]; std::vector txidoprets; cJSON *params = payments_reparse(&n,jsonstr); mypk = pubkey2pk(Mypubkey()); Paymentspk = GetUnspendable(cp,0); @@ -352,13 +352,14 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) checkallocations += allocation; if ( opret.size() > 0 ) { - scriptPubKey.resize(opret.size()); + onlyopret.resize(opret.size()); memcpy(&onlyopret[0],&opret[0],opret.size()); numoprets++; } } else break; mtx.vout.push_back(vout); } + result.push_back(Pair("numoprets",(int64_t)numoprets)); if ( i != m ) { result.push_back(Pair("result","error")); @@ -382,29 +383,35 @@ UniValue PaymentsRelease(struct CCcontract_info *cp,char *jsonstr) { result.push_back(Pair("result","error")); result.push_back(Pair("error","too many oprets")); - result.push_back(Pair("numoprets",(int64_t)numoprets)); if ( params != 0 ) free_json(params); return(result); } + newamount = amount; for (i=0; i= amount ) + if ( (inputsum= AddPaymentsInputs(cp,mtx,txidpk,newamount+2*PAYMENTS_TXFEE,CC_MAXVINS/2,createtxid,latestheight)) >= newamount+2*PAYMENTS_TXFEE ) { std::string rawtx; - if ( (CCchange= (inputsum - amount)) >= PAYMENTS_TXFEE ) - mtx.vout[0].nValue = CCchange-PAYMENTS_TXFEE; + if ( (CCchange= (inputsum - newamount - 2*PAYMENTS_TXFEE)) >= PAYMENTS_TXFEE ) + mtx.vout[0].nValue = CCchange; mtx.vout.push_back(CTxOut(PAYMENTS_TXFEE,CScript() << ParseHex(HexStr(txidpk)) << OP_CHECKSIG)); GetCCaddress1of2(cp,destaddr,Paymentspk,txidpk); CCaddr1of2set(cp,Paymentspk,txidpk,cp->CCpriv,destaddr); rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,onlyopret); if ( params != 0 ) free_json(params); - return(payments_rawtxresult(result,rawtx,1)); + result.push_back(Pair("amount",ValueFromAmount(amount))); + result.push_back(Pair("newamount",ValueFromAmount(newamount))); + return(payments_rawtxresult(result,rawtx,0)); } else { @@ -624,34 +631,38 @@ UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr) for (i=0; i scriptPubKey,opret; - obj.push_back(Pair("txidopret",txidoprets[i].GetHex())); + obj.push_back(Pair("txid",txidoprets[i].GetHex())); if ( myGetTransaction(txidoprets[i],txO,hashBlock) != 0 && txO.vout.size() > 1 && DecodePaymentsTxidOpRet(txO.vout[txO.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' ) { - outstr = (char *)malloc(scriptPubKey.size() + opret.size() + 1); + outstr = (char *)malloc(2*(scriptPubKey.size() + opret.size()) + 1); for (j=0; j 1 ) { result.push_back(Pair("result","error")); result.push_back(Pair("error","too many opreturns")); - result.push_back(Pair("numoprets",(int64_t)numoprets)); } else { + result.push_back(Pair("txidoprets",a)); txidpk = CCtxidaddr(txidaddr,createtxid); GetCCaddress1of2(cp,fundsaddr,Paymentspk,txidpk); funds = CCaddress_balance(fundsaddr); diff --git a/src/cc/rogue/things.c b/src/cc/rogue/things.c index 39c7b94b7..e0cf48454 100644 --- a/src/cc/rogue/things.c +++ b/src/cc/rogue/things.c @@ -527,6 +527,7 @@ add_line(struct rogue_state *rs,char *fmt, char *arg) touchwin(tw); wrefresh(tw); wait_for(rs,' '); + if (md_hasclreol()) { werase(tw); @@ -543,16 +544,31 @@ add_line(struct rogue_state *rs,char *fmt, char *arg) } else { + char *promptex = "--Wait 5 sec.--"; wmove(hw, LINES - 1, 0); - waddstr(hw, prompt); + waddstr(hw, newpage ? promptex : prompt); wrefresh(hw); - wait_for(rs,' '); + + if (newpage) { + + #ifdef _WIN32 + #ifdef _MSC_VER + #define sleep(x) Sleep(1000*(x)) + #endif + #endif + sleep(5); + + } else + wait_for(rs, ' '); + clearok(curscr, TRUE); wclear(hw); + touchwin(stdscr); } newpage = TRUE; line_cnt = 0; + maxlen = (int) strlen(prompt); } if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0')) diff --git a/src/komodo_defs.h b/src/komodo_defs.h index cbf84b7f0..23f291a20 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -81,5 +81,6 @@ extern int32_t USE_EXTERNAL_PUBKEY; int tx_height( const uint256 &hash ); extern char NOTARYADDRS[64][36]; extern uint8_t NUM_NOTARIES; +void komodo_netevent(std::vector payload); #endif diff --git a/src/main.cpp b/src/main.cpp index ce0760cf5..e520ad83f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7035,8 +7035,19 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, Misbehaving(pfrom->GetId(), 1); return false; } - - + else if ( strCommand == "events" ) + { + int32_t i; + if ( ASSETCHAINS_CCLIB != "gamescc" ) + { + Misbehaving(pfrom->GetId(), 1); + return false; + } + std::vector payload; + vRecv >> payload; + komodo_netevent(payload); + return(true); + } else if (strCommand == "verack") { pfrom->SetRecvVersion(min(pfrom->nVersion, PROTOCOL_VERSION)); diff --git a/src/miner.cpp b/src/miner.cpp index 2069e5a8c..eaba96ee1 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -931,6 +931,23 @@ CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey, int32_t nHeight, return CreateNewBlock(pubkey, scriptPubKey, gpucount, isStake); } +void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,std::vector payload) +{ + int32_t numsent = 0; + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + if ( pnode->hSocket == INVALID_SOCKET ) + continue; + if ( numsent < minpeers || (rand() % 10) == 0 ) + { + pnode->PushMessage(message,payload); + if ( numsent++ > maxpeers ) + break; + } + } +} + void komodo_broadcast(CBlock *pblock,int32_t limit) { if (IsInitialBlockDownload()) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 80ad2afe0..f20a63664 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -5653,7 +5653,7 @@ UniValue payments_list(const UniValue& params, bool fHelp) const CKeyStore& keystore = *pwalletMain; LOCK2(cs_main, pwalletMain->cs_wallet); cp = CCinit(&C,EVAL_PAYMENTS); - return(PaymentsList(cp)); + return(PaymentsList(cp,(char *)"")); } UniValue oraclesaddress(const UniValue& params, bool fHelp)