diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 41dfe8cc1..b6ba2eb93 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -55,6 +55,8 @@ CClib_methods[] = { (char *)"faucet2", (char *)"get", (char *)"", 0, 0, 'G', EVAL_FAUCET2 }, #ifdef BUILD_ROGUE { (char *)"rogue", (char *)"newgame", (char *)"buyin", 0, 1, 'N', EVAL_ROGUE }, + { (char *)"rogue", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_ROGUE }, + { (char *)"rogue", (char *)"pending", (char *)"", 0, 0, 'U', EVAL_ROGUE }, { (char *)"rogue", (char *)"register", (char *)"txid [inventory]", 1, 2, 'R', EVAL_ROGUE }, { (char *)"rogue", (char *)"progress", (char *)"txid fname", 2, 2, 'P', EVAL_ROGUE }, { (char *)"rogue", (char *)"claimwin", (char *)"txid", 1, 1, 'W', EVAL_ROGUE }, @@ -76,6 +78,11 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C { return(true); } +UniValue rogue_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue rogue_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue rogue_progress(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue rogue_claimwin(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #else bool sudoku_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); @@ -92,6 +99,23 @@ UniValue CClib_method(struct CCcontract_info *cp,char *method,cJSON *params) if ( cp->evalcode == EVAL_ROGUE ) { rogue_replay(777); + if ( strcmp(method,"newgame") == 0 ) + return(rogue_newgame(txfee,cp,params)); + else if ( strcmp(method,"register") == 0 ) + return(rogue_register(txfee,cp,params)); + else if ( strcmp(method,"progress") == 0 ) + return(rogue_progress(txfee,cp,params)); + else if ( strcmp(method,"claimwin") == 0 ) + return(rogue_claimwin(txfee,cp,params)); + else if ( strcmp(method,"extract") == 0 ) + return(rogue_extract(txfee,cp,params)); + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","invalid rogue method")); + result.push_back(Pair("method",method)); + return(result); + } } #else if ( cp->evalcode == EVAL_SUDOKU ) @@ -406,6 +430,7 @@ std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *para } #ifdef BUILD_ROGUE +#include "rogue_rpc.cpp" #include "rogue/vers.c" #include "rogue/extern.c" #include "rogue/armor.c" diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp new file mode 100644 index 000000000..536b6e590 --- /dev/null +++ b/src/cc/rogue_rpc.cpp @@ -0,0 +1,398 @@ + +/****************************************************************************** + * Copyright © 2014-2019 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include "cJSON.h" + + +//////////////////////// start of CClib interface + + +CScript rogue_newgameopret(int64_t buyin) +{ + CScript opret; uint8_t evalcode = EVAL_ROGUE; + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'G' << buyin); + return(opret); +} + +/*CScript rogue_solutionopret(char *solution,uint32_t timestamps[81]) +{ + CScript opret; uint8_t evalcode = EVAL_ROGUE; std::string str(solution); std::vector data; int32_t i; + for (i=0; i<81; i++) + { + data.push_back((timestamps[i] >> 24) & 0xff); + data.push_back((timestamps[i] >> 16) & 0xff); + data.push_back((timestamps[i] >> 8) & 0xff); + data.push_back(timestamps[i] & 0xff); + } + opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'S' << str << data); + return(opret); +} + +uint8_t rogue_solutionopreturndecode(char solution[82],uint32_t timestamps[81],CScript scriptPubKey) +{ + std::vector vopret; uint8_t *script,e,f; std::string str; std::vector data; int32_t i,ind; uint32_t x; + GetOpReturnData(scriptPubKey,vopret); + script = (uint8_t *)vopret.data(); + if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> str; ss >> data) != 0 && e == EVAL_ROGUE && f == 'S' ) + { + if ( data.size() == 81*sizeof(uint32_t) && str.size() == 81 ) + { + strcpy(solution,str.c_str()); + for (i=ind=0; i<81; i++) + { + if ( solution[i] < '1' || solution[i] > '9' ) + break; + x = data[ind++]; + x <<= 8, x |= (data[ind++] & 0xff); + x <<= 8, x |= (data[ind++] & 0xff); + x <<= 8, x |= (data[ind++] & 0xff); + timestamps[i] = x; + } + if ( i == 81 ) + return(f); + } else fprintf(stderr,"datasize %d sol[%d]\n",(int32_t)data.size(),(int32_t)str.size()); + } + return(0); +}*/ + +uint8_t rogue_newgameopreturndecode(int64_t &buyin,CScript scriptPubKey) +{ + 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 >> buyin) != 0 && e == EVAL_ROGUE && f == 'G' ) + { + return(f); + } + return(0); +} + +UniValue rogue_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + CPubKey roguepk,mypk; char *jsonstr; uint64_t inputsum,amount = 0; + if ( params != 0 ) + { + if ( (jsonstr= jprint(params,0)) != 0 ) + { + if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' ) + { + jsonstr[strlen(jsonstr)-1] = 0; + jsonstr++; + } + amount = atof(jsonstr) * COIN + 0.0000000049; + free(jsonstr); + } + } + mypk = pubkey2pk(Mypubkey()); + roguepk = GetUnspendable(cp,0); + result.push_back(Pair("result","success")); + result.push_back(Pair("name","rogue")); + result.push_back(Pair("method","newgame")); + if ( amount == 0 ) + result.push_back(Pair("type","newbie")); + else result.push_back(Pair("type","buyin")); + result.push_back(Pair("amount",ValueFromAmount(amount))); + if ( (inputsum= AddCClibInputs(cp,mtx,roguepk,3*txfee,16,cp->unspendableCCaddr)) >= 3*txfee ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,roguepk)); + mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,mypk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,rogue_newgameopret(amount)); + if ( rawtx.size() > 0 ) + { + CTransaction tx; + result.push_back(Pair("hex",rawtx)); + if ( DecodeHexTx(tx,rawtx) != 0 ) + result.push_back(Pair("txid",tx.GetHash().ToString())); + } else result.push_back(Pair("error","couldnt finalize CCtx")); + } + return(result); +} + +UniValue rogue_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + return(result); +} + +UniValue rogue_progress(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + return(result); +} + +UniValue rogue_claimwin(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + return(result); +} + +UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); + return(result); +} + +UniValue rogue_txidinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); int32_t numvouts; char CCaddr[64],str[65],*txidstr; uint256 txid,hashBlock; CTransaction tx; uint64_t amount; CBlockIndex *pindex; + if ( params != 0 ) + { + result.push_back(Pair("result","success")); + if ( (txidstr= jprint(params,0)) != 0 ) + { + if ( txidstr[0] == '"' && txidstr[strlen(txidstr)-1] == '"' ) + { + txidstr[strlen(txidstr)-1] = 0; + txidstr++; + } + //printf("params -> (%s)\n",txidstr); + decode_hex((uint8_t *)&txid,32,txidstr); + txid = revuint256(txid); + result.push_back(Pair("txid",txid.GetHex())); + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + if ( rogue_newgameopreturndecode(buyin,tx.vout[numvouts-1].scriptPubKey) == 'G' ) + { + result.push_back(Pair("result","success")); + if ( (pindex= komodo_blockindex(hashBlock)) != 0 ) + result.push_back(Pair("height",pindex->GetHeight())); + Getscriptaddress(CCaddr,tx.vout[1].scriptPubKey); + result.push_back(Pair("rogueaddr",CCaddr)); + result.push_back(Pair("buyin",ValueFromAmount(buyin))); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt extract rogue_generate opreturn")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt find txid")); + } + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","missing txid in params")); + } + result.push_back(Pair("name","rogue")); + result.push_back(Pair("method","txidinfo")); + return(result); +} + +UniValue rogue_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ),a(UniValue::VARR); + char coinaddr[64]; uint64_t seed; int64_t nValue,total=0; uint256 txid,hashBlock; CTransaction tx; int32_t ht,vout,numvouts; CPubKey roguepk; CBlockIndex *pindex; + std::vector > unspentOutputs; + roguepk = GetUnspendable(cp,0); + GetCCaddress(cp,coinaddr,roguepk); + SetCCunspents(unspentOutputs,coinaddr); + for (std::vector >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++) + { + txid = it->first.txhash; + vout = (int32_t)it->first.index; + //char str[65]; fprintf(stderr,"%s check %s/v%d %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN); + if ( it->second.satoshis != txfee || vout != 0 ) + continue; + if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + if ( (nValue= IsCClibvout(cp,tx,vout,coinaddr)) == txfee && myIsutxo_spentinmempool(txid,vout) == 0 ) + { + if ( rogue_newgameopreturndecode(amount,tx.vout[numvouts-1].scriptPubKey) == 'G' ) + { + UniValue obj(UniValue::VOBJ); + if ( (pindex= komodo_blockindex(hashBlock)) != 0 ) + { + ht = pindex->GetHeight(); + obj.push_back(Pair("height",ht)); + obj.push_back(Pair("start",ht+10)); + if ( komodo_nextheight() > ht+10 ) + { + if ( pindex= komodo_chainactive(ht+10)) != 0 ) + { + hashBlock = pindex->GetBlockHash(); + obj.push_back(Pair("starthash",hashBlock.ToString().c_str())); + memset(&seed,&hashBlock,sizeof(seed)); + seed &= (1LL << 63) - 1; + obj.push_back(Pair("seed",(int64_t)seed)); + } + } + } + obj.push_back(Pair("buyin",ValueFromAmount(amount))); + obj.push_back(Pair("txid",txid.GetHex())); + a.push_back(obj); + total += amount; + } + } + } + } + result.push_back(Pair("result","success")); + result.push_back(Pair("name","rogue")); + result.push_back(Pair("method","pending")); + result.push_back(Pair("pending",a)); + result.push_back(Pair("numpending",a.size())); + result.push_back(Pair("total",ValueFromAmount(total))); + return(result); +} + +#ifdef notyest +UniValue rogue_solution(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); int32_t i,j,good,ind,n,numvouts; uint256 txid; char *jsonstr,*newstr,*txidstr,coinaddr[64],checkaddr[64],CCaddr[64],*solution=0,unsolved[82]; CPubKey pk,mypk; uint8_t vals9[9][9],priv32[32],pub33[33]; uint32_t timestamps[81]; uint64_t balance,inputsum; std::string rawtx; CTransaction tx; uint256 hashBlock; + mypk = pubkey2pk(Mypubkey()); + memset(timestamps,0,sizeof(timestamps)); + result.push_back(Pair("name","rogue")); + result.push_back(Pair("method","solution")); + good = 0; + if ( params != 0 ) + { + if ( (jsonstr= jprint(params,0)) != 0 ) + { + if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' ) + { + jsonstr[strlen(jsonstr)-1] = 0; + jsonstr++; + } + newstr = (char *)malloc(strlen(jsonstr)+1); + for (i=j=0; jsonstr[i]!=0; i++) + { + if ( jsonstr[i] == '%' && jsonstr[i+1] == '2' && jsonstr[i+2] == '2' ) + { + newstr[j++] = '"'; + i += 2; + } else newstr[j++] = jsonstr[i]; + } + newstr[j] = 0; + params = cJSON_Parse(newstr); + } else params = 0; + if ( params != 0 ) + { + if ( (n= cJSON_GetArraySize(params)) > 2 && n <= (sizeof(timestamps)/sizeof(*timestamps))+2 ) + { + for (i=2; i '9' ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","illegal solution")); + return(result); + } + vals9[i][j] = solution[ind++] - '0'; + } + rogue_privkey(priv32,vals9); + priv2addr(coinaddr,pub33,priv32); + pk = buf2pk(pub33); + GetCCaddress(cp,CCaddr,pk); + result.push_back(Pair("rogueaddr",CCaddr)); + balance = CCaddress_balance(CCaddr); + result.push_back(Pair("amount",ValueFromAmount(balance))); + if ( rogue_captcha(1,timestamps,komodo_nextheight()) < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","captcha failure")); + return(result); + } + else + { + if ( (txidstr= jstri(params,0)) != 0 ) + { + decode_hex((uint8_t *)&txid,32,txidstr); + txid = revuint256(txid); + result.push_back(Pair("txid",txid.GetHex())); + if ( CCgettxout(txid,0,1) < 0 ) + result.push_back(Pair("error","already solved")); + else if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 1 ) + { + Getscriptaddress(checkaddr,tx.vout[1].scriptPubKey); + if ( strcmp(checkaddr,CCaddr) != 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","wrong solution")); + result.push_back(Pair("yours",CCaddr)); + return(result); + } + if ( rogue_genopreturndecode(unsolved,tx.vout[numvouts-1].scriptPubKey) == 'G' ) + { + for (i=0; i<81; i++) + { + if ( unsolved[i] < '1' || unsolved[i] > '9') + continue; + else if ( unsolved[i] != solution[i] ) + { + printf("i.%d [%c] != [%c]\n",i,unsolved[i],solution[i]); + result.push_back(Pair("error","wrong rogue solved")); + break; + } + } + if ( i == 81 ) + good = 1; + } else result.push_back(Pair("error","cant decode rogue")); + } else result.push_back(Pair("error","couldnt find rogue")); + } + if ( good != 0 ) + { + mtx.vin.push_back(CTxIn(txid,0,CScript())); + if ( (inputsum= AddCClibInputs(cp,mtx,pk,balance,16,CCaddr)) >= balance ) + { + mtx.vout.push_back(CTxOut(balance,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); + CCaddr2set(cp,cp->evalcode,pk,priv32,CCaddr); + rawtx = FinalizeCCTx(0,cp,mtx,pubkey2pk(Mypubkey()),txfee,rogue_solutionopret(solution,timestamps)); + if ( rawtx.size() > 0 ) + { + result.push_back(Pair("result","success")); + result.push_back(Pair("hex",rawtx)); + } + else result.push_back(Pair("error","couldnt finalize CCtx")); + } else result.push_back(Pair("error","couldnt find funds in solution address")); + } + } + } + } + else + { + printf("n.%d params.(%s)\n",n,jprint(params,0)); + result.push_back(Pair("error","couldnt get all params")); + } + return(result); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse parameters")); + result.push_back(Pair("parameters",newstr)); + return(result); + } + } + result.push_back(Pair("result","error")); + result.push_back(Pair("error","missing parameters")); + return(result); +} +#endif +