diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index b2fa534a1..0afb47894 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -59,13 +59,16 @@ static bool fDaemon; #include "komodo_defs.h" #define KOMODO_ASSETCHAIN_MAXLEN 65 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +extern uint32_t ASSETCHAINS_BLOCKTIME; +extern uint64_t ASSETCHAINS_CBOPRET; void komodo_passport_iteration(); uint64_t komodo_interestsum(); int32_t komodo_longestchain(); +void komodo_cbopretupdate(); void WaitForShutdown(boost::thread_group* threadGroup) { - bool fShutdown = ShutdownRequested(); + int32_t i; bool fShutdown = ShutdownRequested(); // Tell the main threads to shutdown. while (!fShutdown) { @@ -73,13 +76,27 @@ void WaitForShutdown(boost::thread_group* threadGroup) if ( ASSETCHAINS_SYMBOL[0] == 0 ) { komodo_passport_iteration(); - MilliSleep(10000); + for (i=0; i<10; i++) + { + fShutdown = ShutdownRequested(); + if ( fShutdown != 0 ) + break; + MilliSleep(1000); + } } else { //komodo_interestsum(); //komodo_longestchain(); - MilliSleep(20000); + if ( ASSETCHAINS_CBOPRET != 0 ) + komodo_cbopretupdate(); + for (i=0; i<=ASSETCHAINS_BLOCKTIME/5; i++) + { + fShutdown = ShutdownRequested(); + if ( fShutdown != 0 ) + break; + MilliSleep(1000); + } } fShutdown = ShutdownRequested(); } diff --git a/src/cc/CCinclude.h b/src/cc/CCinclude.h index 13d7236d4..12b4a6d12 100644 --- a/src/cc/CCinclude.h +++ b/src/cc/CCinclude.h @@ -197,6 +197,7 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c 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); +int32_t komodo_blockload(CBlock& block,CBlockIndex *pindex); 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); @@ -247,6 +248,7 @@ void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, c int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode); bool IsCCInput(CScript const& scriptSig); +bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime); int32_t unstringbits(char *buf,uint64_t bits); uint64_t stringbits(char *str); uint256 revuint256(uint256 txid); diff --git a/src/cc/CCutils.cpp b/src/cc/CCutils.cpp index a3bf0a68b..887550a0c 100644 --- a/src/cc/CCutils.cpp +++ b/src/cc/CCutils.cpp @@ -168,6 +168,18 @@ bool IsCCInput(CScript const& scriptSig) return true; } +bool CheckTxFee(const CTransaction &tx, uint64_t txfee, uint32_t height, uint64_t blocktime) +{ + int64_t interest; uint64_t valuein; + CCoinsViewCache &view = *pcoinsTip; + valuein = view.GetValueIn(height,&interest,tx,blocktime); + if ( valuein-tx.GetValueOut() > txfee ) + { + //fprintf(stderr, "txfee.%li vs txfee.%li\n", valuein-tx.GetValueOut(), txfee); + return false; + } + return true; +} // set additional 'unspendable' addr void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr) @@ -668,4 +680,4 @@ bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector paramsNull,co return(false); //eval->Invalid("error in CClib_validate"); } return eval->Invalid("cclib CC must have evalcode between 16 and 127"); -} \ No newline at end of file +} diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 95748def4..00a7c6fe0 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -52,6 +52,8 @@ std::string MYCCLIBNAME = (char *)"sudoku"; void komodo_netevent(std::vector payload) {} #endif +extern std::string MYCCLIBNAME; + char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); } struct CClib_rpcinfo @@ -691,8 +693,8 @@ int32_t cclib_parsehash(uint8_t *hash32,cJSON *item,int32_t len) #include "customcc.cpp" #elif BUILD_GAMESCC -#include "gamescc.cpp" #include "rogue/cursesd.c" +#include "gamescc.cpp" #else #include "sudoku.cpp" diff --git a/src/cc/dapps/dappstd.c b/src/cc/dapps/dappstd.c new file mode 100644 index 000000000..82366315c --- /dev/null +++ b/src/cc/dapps/dappstd.c @@ -0,0 +1,1119 @@ +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ + +// requires CHAINNAME and GAMEMAIN() to be #defined + +#include +#include +#include +#include +#include +#include +#include + +extern struct games_state globalR; +void *gamesiterate(struct games_state *rs); + +char USERPASS[8192]; uint16_t GAMES_PORT; +char Gametxidstr[67]; +char *clonestr(char *str); + +#define MAXSTR 1024 +char whoami[MAXSTR]; + +#define SMALLVAL 0.000000000000001 +#define SATOSHIDEN ((uint64_t)100000000L) +#define dstr(x) ((double)(x) / SATOSHIDEN) +#define KOMODO_ASSETCHAIN_MAXLEN 65 +char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],IPADDRESS[100]; + +#ifndef _BITS256 +#define _BITS256 +union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; +typedef union _bits256 bits256; +#endif + +#ifdef _WIN32 +#ifdef _MSC_VER +int gettimeofday(struct timeval * tp, struct timezone * tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's + static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime(&system_time); + SystemTimeToFileTime(&system_time, &file_time); + time = ((uint64_t)file_time.dwLowDateTime); + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long)((time - EPOCH) / 10000000L); + tp->tv_usec = (long)(system_time.wMilliseconds * 1000); + return 0; +} +#endif // _MSC_VER +#endif + +double OS_milliseconds() +{ + struct timeval tv; double millis; +#ifdef __MINGW32__ + mingw_gettimeofday(&tv,NULL); +#else + gettimeofday(&tv,NULL); +#endif + millis = ((double)tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.); + //printf("tv_sec.%ld usec.%d %f\n",tv.tv_sec,tv.tv_usec,millis); + return(millis); +} + +int32_t _unhex(char c) +{ + if ( c >= '0' && c <= '9' ) + return(c - '0'); + else if ( c >= 'a' && c <= 'f' ) + return(c - 'a' + 10); + else if ( c >= 'A' && c <= 'F' ) + return(c - 'A' + 10); + return(-1); +} + +int32_t is_hexstr(char *str,int32_t n) +{ + int32_t i; + if ( str == 0 || str[0] == 0 ) + return(0); + for (i=0; str[i]!=0; i++) + { + if ( n > 0 && i >= n ) + break; + if ( _unhex(str[i]) < 0 ) + break; + } + if ( n == 0 ) + return(i); + return(i == n); +} + +int32_t unhex(char c) +{ + int32_t hex; + if ( (hex= _unhex(c)) < 0 ) + { + //printf("unhex: illegal hexchar.(%c)\n",c); + } + return(hex); +} + +unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); } + +int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex) +{ + int32_t adjust,i = 0; + //printf("decode.(%s)\n",hex); + if ( is_hexstr(hex,n) <= 0 ) + { + memset(bytes,0,n); + return(n); + } + if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) + hex[--n] = 0; + if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) ) + { + if ( n > 0 ) + { + bytes[0] = unhex(hex[0]); + printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex)); + } + bytes++; + hex++; + adjust = 1; + } else adjust = 0; + if ( n > 0 ) + { + for (i=0; i>4) & 0xf); + hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf); + //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]); + } + hexbytes[len*2] = 0; + //printf("len.%ld\n",len*2+1); + return((int32_t)len*2+1); +} + +char *bits256_str(char hexstr[65],bits256 x) +{ + init_hexbytes_noT(hexstr,x.bytes,sizeof(x)); + return(hexstr); +} + +long _stripwhite(char *buf,int accept) +{ + int32_t i,j,c; + if ( buf == 0 || buf[0] == 0 ) + return(0); + for (i=j=0; buf[i]!=0; i++) + { + buf[j] = c = buf[i]; + if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') ) + j++; + } + buf[j] = 0; + return(j); +} + +char *parse_conf_line(char *line,char *field) +{ + line += strlen(field); + for (; *line!='='&&*line!=0; line++) + break; + if ( *line == 0 ) + return(0); + if ( *line == '=' ) + line++; + while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' ) + line[strlen(line)-1] = 0; + //printf("LINE.(%s)\n",line); + _stripwhite(line,0); + return(clonestr(line)); +} + +int32_t safecopy(char *dest,char *src,long len) +{ + int32_t i = -1; + if ( src != 0 && dest != 0 && src != dest ) + { + if ( dest != 0 ) + memset(dest,0,len); + for (i=0; i buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); + } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; + } + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); +} + +uint8_t *OS_fileptr(long *allocsizep,char *fname) +{ + long filesize = 0; uint8_t *buf = 0; void *retptr; + *allocsizep = 0; + retptr = OS_loadfile(fname,&buf,&filesize,allocsizep); + return((uint8_t *)retptr); +} + +struct MemoryStruct { char *memory; size_t size; }; +struct return_string { char *ptr; size_t len; }; + +// return data from the server +#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) +#define CURL_GLOBAL_SSL (1<<0) +#define CURL_GLOBAL_WIN32 (1<<1) + + +/************************************************************************ + * + * Initialize the string handler so that it is thread safe + * + ************************************************************************/ + +void init_string(struct return_string *s) +{ + s->len = 0; + s->ptr = (char *)calloc(1,s->len+1); + if ( s->ptr == NULL ) + { + fprintf(stderr,"init_string malloc() failed\n"); + exit(-1); + } + s->ptr[0] = '\0'; +} + +/************************************************************************ + * + * Use the "writer" to accumulate text until done + * + ************************************************************************/ + +size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s) +{ + size_t new_len = s->len + size*nmemb; + s->ptr = (char *)realloc(s->ptr,new_len+1); + if ( s->ptr == NULL ) + { + fprintf(stderr, "accumulate realloc() failed\n"); + exit(-1); + } + memcpy(s->ptr+s->len,ptr,size*nmemb); + s->ptr[new_len] = '\0'; + s->len = new_len; + return(size * nmemb); +} + +/************************************************************************ + * + * return the current system time in milliseconds + * + ************************************************************************/ + +#define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field +#ifdef EXTRACT_BITCOIND_RESULT + +/************************************************************************ + * + * perform post processing of the results + * + ************************************************************************/ + +char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params) +{ + long i,j,len; char *retstr = 0; cJSON *json,*result,*error; + //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); + if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) + { + if ( strcmp(command,"signrawtransaction") != 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); + return(rpcstr); + } + json = cJSON_Parse(rpcstr); + if ( json == 0 ) + { + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params); + free(rpcstr); + return(0); + } + result = cJSON_GetObjectItem(json,"result"); + error = cJSON_GetObjectItem(json,"error"); + if ( error != 0 && result != 0 ) + { + if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL ) + { + retstr = cJSON_Print(result); + len = strlen(retstr); + if ( retstr[0] == '"' && retstr[len-1] == '"' ) + { + for (i=1,j=0; itype&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) + { + if ( strcmp(command,"signrawtransaction") != 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); + } + free(rpcstr); + } else retstr = rpcstr; + free_json(json); + //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr); + return(retstr); +} +#endif + +#ifdef _WIN32 +#ifdef _MSC_VER +#define sleep(x) Sleep(1000*(x)) +#endif +#endif + +/************************************************************************ + * + * perform the query + * + ************************************************************************/ + +char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) +{ + static int didinit,count,count2; static double elapsedsum,elapsedsum2; + struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; + char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime; + if ( didinit == 0 ) + { + didinit = 1; + curl_global_init(CURL_GLOBAL_ALL); //init the curl session + } + numretries = 0; + if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) + specialcase = 1; + else specialcase = 0; + if ( url[0] == 0 ) + strcpy(url,"http://127.0.0.1:7876/nxt"); + if ( specialcase != 0 && 0 ) + printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); +try_again: + if ( retstrp != 0 ) + *retstrp = 0; + starttime = OS_milliseconds(); + curl_handle = curl_easy_init(); + init_string(&s); + headers = curl_slist_append(0,"Expect:"); + + curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl_handle,CURLOPT_URL, url); + curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function + curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback + curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash + curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback + if ( strncmp(url,"https",5) == 0 ) + { + curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); + curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); + } + if ( userpass != 0 ) + curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); + databuf = 0; + if ( params != 0 ) + { + if ( command != 0 && specialcase == 0 ) + { + len = strlen(params); + if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) { + bracket0 = bracket1 = (char *)""; + } + else + { + bracket0 = (char *)"["; + bracket1 = (char *)"]"; + } + + databuf = (char *)malloc(256 + strlen(command) + strlen(params)); + sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); + //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); + // + } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); + curl_easy_setopt(curl_handle,CURLOPT_POST,1L); + if ( databuf != 0 ) + curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf); + else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params); + } + //laststart = milliseconds(); + res = curl_easy_perform(curl_handle); + curl_slist_free_all(headers); + curl_easy_cleanup(curl_handle); + if ( databuf != 0 ) // clean up temporary buffer + { + free(databuf); + databuf = 0; + } + if ( res != CURLE_OK ) + { + numretries++; + if ( specialcase != 0 ) + { + printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); + free(s.ptr); + return(0); + } + else if ( numretries >= 1 ) + { + //printf("Maximum number of retries exceeded!\n"); + free(s.ptr); + return(0); + } + if ( (rand() % 1000) == 0 ) + printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); + free(s.ptr); + sleep((1< (%s)\n",params,s.ptr); + count2++; + elapsedsum2 += (OS_milliseconds() - starttime); + if ( (count2 % 10000) == 0) + printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command); + return(s.ptr); + } + } + printf("bitcoind_RPC: impossible case\n"); + free(s.ptr); + return(0); +} + +static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data) +{ + size_t realsize = (size * nmemb); + struct MemoryStruct *mem = (struct MemoryStruct *)data; + mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1)); + if ( mem->memory != 0 ) + { + if ( ptr != 0 ) + memcpy(&(mem->memory[mem->size]),ptr,realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + //printf("got %d bytes\n",(int32_t)(size*nmemb)); + return(realsize); +} + +char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) +{ + struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0; + if ( (cHandle= *cHandlep) == NULL ) + *cHandlep = cHandle = curl_easy_init(); + else curl_easy_reset(cHandle); + //#ifdef DEBUG + //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1); + //#endif + curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0); + //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1); + curl_easy_setopt(cHandle,CURLOPT_URL,url); + curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10); + if ( userpass != 0 && userpass[0] != 0 ) + curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass); + if ( postfields != 0 && postfields[0] != 0 ) + { + curl_easy_setopt(cHandle,CURLOPT_POST,1); + curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields); + } + if ( hdr0 != NULL && hdr0[0] != 0 ) + { + //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:""); + headers = curl_slist_append(headers,hdr0); + if ( hdr1 != 0 && hdr1[0] != 0 ) + headers = curl_slist_append(headers,hdr1); + if ( hdr2 != 0 && hdr2[0] != 0 ) + headers = curl_slist_append(headers,hdr2); + if ( hdr3 != 0 && hdr3[0] != 0 ) + headers = curl_slist_append(headers,hdr3); + } //headers = curl_slist_append(0,"Expect:"); + if ( headers != 0 ) + curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers); + //res = curl_easy_perform(cHandle); + memset(&chunk,0,sizeof(chunk)); + curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback); + curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk); + curl_easy_perform(cHandle); + curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code); + if ( headers != 0 ) + curl_slist_free_all(headers); + if ( code != 200 ) + printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory); + return(chunk.memory); +} + +uint16_t _komodo_userpass(char *username, char *password, FILE *fp) +{ + char *rpcuser,*rpcpassword,*str,*ipaddress,line[8192]; uint16_t port = 0; + rpcuser = rpcpassword = 0; + username[0] = password[0] = 0; + while ( fgets(line,sizeof(line),fp) != 0 ) + { + if ( line[0] == '#' ) + continue; + //printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword")); + if ( (str= strstr(line,(char *)"rpcuser")) != 0 ) + rpcuser = parse_conf_line(str,(char *)"rpcuser"); + else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 ) + rpcpassword = parse_conf_line(str,(char *)"rpcpassword"); + else if ( (str= strstr(line,(char *)"rpcport")) != 0 ) + { + port = atoi(parse_conf_line(str,(char *)"rpcport")); + //fprintf(stderr,"rpcport.%u in file\n",port); + } + else if ( (str= strstr(line,(char *)"ipaddress")) != 0 ) + { + ipaddress = parse_conf_line(str,(char *)"ipaddress"); + strcpy(IPADDRESS,ipaddress); + } + } + if ( rpcuser != 0 && rpcpassword != 0 ) + { + strcpy(username,rpcuser); + strcpy(password,rpcpassword); + } + //printf("rpcuser.(%s) rpcpassword.(%s) %u ipaddress.%s\n",rpcuser,rpcpassword,port,ipaddress); + if ( rpcuser != 0 ) + free(rpcuser); + if ( rpcpassword != 0 ) + free(rpcpassword); + return(port); +} + +uint16_t komodo_userpass(char *userpass,char *symbol) +{ + FILE *fp; uint16_t port = 0; char fname[512],username[512],password[512],confname[KOMODO_ASSETCHAIN_MAXLEN]; + userpass[0] = 0; + if ( strcmp("KMD",symbol) == 0 ) + { +#ifdef __APPLE__ + sprintf(confname,"Komodo.conf"); +#else + sprintf(confname,"komodo.conf"); +#endif + } + else sprintf(confname,"%s.conf",symbol); + //komodo_statefname(fname,symbol,confname); + if ( (fp= fopen(confname,"rb")) != 0 ) + { + port = _komodo_userpass(username,password,fp); + sprintf(userpass,"%s:%s",username,password); + if ( strcmp(symbol,ASSETCHAINS_SYMBOL) == 0 ) + strcpy(USERPASS,userpass); + fclose(fp); + } + return(port); +} + +#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True) + +char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) +{ + //static void *cHandle; + char url[512],*retstr=0,*retstr2=0,postdata[8192]; + if ( params == 0 || params[0] == 0 ) + params = (char *)"[]"; + if ( strlen(params) < sizeof(postdata)-128 ) + { + sprintf(url,(char *)"http://%s:%u",IPADDRESS,port); + sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); + //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,USERPASS); + retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); + //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); + } + return(retstr2); +} + +int32_t games_sendrawtransaction(char *rawtx) +{ + char *params,*retstr,*hexstr; cJSON *retjson,*resobj; int32_t retval = -1; + params = (char *)malloc(strlen(rawtx) + 16); + sprintf(params,"[\"%s\"]",rawtx); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"sendrawtransaction",params,GAMES_PORT)) != 0 ) + { + if ( 0 ) // causes 4th level crash + { + static FILE *fp; + if ( fp == 0 ) + fp = fopen("games.sendlog","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%s\n",retstr); + fflush(fp); + } + } + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + if ( (hexstr= jstr(resobj,0)) != 0 && is_hexstr(hexstr,64) == 64 ) + retval = 0; + } + free_json(retjson); + } + + /* log sendrawtx result in file */ + + /* + FILE *debug_file; + debug_file = fopen("tx_debug.log", "a"); + fprintf(debug_file, "%s\n", retstr); + fflush(debug_file); + fclose(debug_file); + */ + + free(retstr); + } + free(params); + return(retval); +} + +int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,gamesevent *keystrokes,int32_t num) +{ + char cmd[16384],hexstr[16384],params[32768],*retstr,*errstr,*rawtx; int32_t i,len,retflag = -1; cJSON *retjson,*resobj; + if ( rs->guiflag != 0 && Gametxidstr[0] != 0 ) + { + if ( rs->keystrokeshex != 0 ) + { + if ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + if ( waitflag == 0 ) + return(0); + else if ( 0 ) + { + while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) + { + //fprintf(stderr,"pre-rebroadcast\n"); + sleep(10); + } + } + } + free(rs->keystrokeshex), rs->keystrokeshex = 0; + } + memset(hexstr,0,sizeof(hexstr)); + for (i=0; ikeystrokeshex != 0 ) + free(rs->keystrokeshex); + if ( (errstr= jstr(resobj,(char *)"error")) == 0 ) + { + rs->keystrokeshex = (char *)malloc(strlen(rawtx)+1); + strcpy(rs->keystrokeshex,rawtx); + retflag = 1; + } else fprintf(stderr,"error sending keystrokes tx\n"), sleep(1); + //fprintf(stderr,"set keystrokestx <- %s\n",rs->keystrokeshex); + } + free_json(retjson); + } + free(retstr); + } + } + return(retflag); +} + +int32_t gamesfname(char *fname,uint64_t seed,int32_t counter) +{ + sprintf(fname,"%s.%llu.%d",GAMENAME,(long long)seed,counter); + return(0); +} + +int32_t flushkeystrokes_local(struct games_state *rs,int32_t waitflag) +{ +#ifdef STANDALONE + char fname[1024]; FILE *fp; int32_t i,retflag = -1; + rs->counter++; + gamesfname(fname,rs->origseed,rs->counter); + if ( (fp= fopen(fname,"wb")) != 0 ) + { + if ( fwrite(rs->buffered,sizeof(*rs->buffered),rs->num,fp) == rs->num ) + { + rs->num = 0; + retflag = 0; + fclose(fp); + gamesfname(fname,rs->origseed,rs->counter+1); + if ( (fp= fopen(fname,"wb")) != 0 ) // truncate next file + fclose(fp); + //fprintf(stderr,"savefile <- %s retflag.%d\n",fname,retflag); + //} + } else fprintf(stderr,"error writing (%s)\n",fname); + } else fprintf(stderr,"error creating (%s)\n",fname); + return(retflag); +#else + return(0); +#endif +} + +#ifndef STANDALONE +// stubs for inside daemon + +int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) +{ + return(0); +} + +int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) +{ + return(-1); +} +#endif + +int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag) +{ + if ( rs->num > 0 ) + { + if ( games_progress(rs,waitflag,rs->origseed,rs->buffered,rs->num) > 0 ) + { + flushkeystrokes_local(rs,waitflag); + memset(rs->buffered,0,sizeof(rs->buffered)); + } + } + return(0); +} + +void gamesbailout(struct games_state *rs) +{ + flushkeystrokes(rs,1); +} + +#ifdef _WIN32 +#ifdef _MSC_VER +#define sleep(x) Sleep(1000*(x)) +#endif +#endif + +long get_filesize(FILE *fp) +{ + long fsize,fpos = ftell(fp); + fseek(fp,0,SEEK_END); + fsize = ftell(fp); + fseek(fp,fpos,SEEK_SET); + return(fsize); +} + +gamesevent *games_keystrokesload(int32_t *numkeysp,uint64_t seed,int32_t counter) +{ + char fname[1024]; gamesevent *keystrokes = 0; FILE *fp; long fsize; int32_t i,num = 0; + *numkeysp = 0; + while ( 1 ) + { + gamesfname(fname,seed,counter); + //printf("check (%s)\n",fname); + if ( (fp= fopen(fname,"rb")) == 0 ) + break; + if ( (fsize= get_filesize(fp)) <= 0 ) + { + fclose(fp); + //printf("fsize.%ld\n",fsize); + break; + } + if ( (keystrokes= (gamesevent *)realloc(keystrokes,sizeof(*keystrokes)*num+fsize)) == 0 ) + { + fprintf(stderr,"error reallocating keystrokes\n"); + fclose(fp); + return(0); + } + if ( fread(&keystrokes[num],1,fsize,fp) != fsize ) + { + fprintf(stderr,"error reading keystrokes from (%s)\n",fname); + fclose(fp); + free(keystrokes); + return(0); + } + fclose(fp); + num += (int32_t)(fsize / sizeof(gamesevent)); + //for (i=0; i 0 ) + { + sprintf(fname,"%s.%llu.player",GAMENAME,(long long)seed); + if ( (fp=fopen(fname,"rb")) != 0 ) + { + if ( fread(&P,1,sizeof(P),fp) > 0 ) + { + //printf("max size player\n"); + player = &P; + } + fclose(fp); + } + games_replay2(0,seed,keystrokes,num,player,sleeptime); + mvaddstr(LINES - 2, 0, (char *)"replay completed"); + endwin(); + games_exit(); + } + if ( keystrokes != 0 ) + free(keystrokes); + return(num); +} + +int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) +{ + char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson; + if ( rs->guiflag == 0 ) + return(-1); + if ( gametxidstr == 0 || *gametxidstr == 0 ) + return(retval); + if ( 0 ) + { + sprintf(fname,"%s.gameinfo",gametxidstr); + sprintf(cmd,"./komodo-cli -ac_name=%s cclib gameinfo 17 \\\"[%%22%s%%22]\\\" > %s",ASSETCHAINS_SYMBOL,gametxidstr,fname); + if ( system(cmd) != 0 ) + fprintf(stderr,"error issuing (%s)\n",cmd); + else filestr = (char *)OS_fileptr(&allocsize,fname); + } + else + { + sprintf(params,"[\"gameinfo\",\"17\",\"[%%22%s%%22]\"]",gametxidstr); + filestr = komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT); + } + if ( filestr != 0 ) + { + if ( (retjson= cJSON_Parse(filestr)) != 0 && (resultjson= jobj(retjson,(char *)"result")) != 0 ) + { + //fprintf(stderr,"gameinfo.(%s)\n",jprint(resultjson,0)); + if ( (array= jarray(&n,resultjson,(char *)"players")) != 0 ) + { + for (i=0; iP,(int32_t)strlen(datastr)/2,datastr); + fprintf(stderr,"set pname[%s] %s\n",pname==0?"":pname,jprint(item,0)); + rs->restoring = 1; + } + } + } + } + } + free_json(retjson); + } + free(filestr); + } + return(retval); +} + +#ifdef _WIN32 +#ifdef _MSC_VER +__inline int msver(void) { + switch (_MSC_VER) { + case 1500: return 2008; + case 1600: return 2010; + case 1700: return 2012; + case 1800: return 2013; + case 1900: return 2015; + //case 1910: return 2017; + default: return (_MSC_VER / 100); + } +} + +static inline bool is_x64(void) { +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) + return 1; +#elif defined(__amd64__) || defined(__amd64) || defined(_M_X64) || defined(_M_IA64) + return 1; +#else + return 0; +#endif +} + +#define BUILD_DATE __DATE__ " " __TIME__ +#endif // _WIN32 +#endif // _MSC_VER + +int main(int argc, char **argv) +{ + uint64_t seed; FILE *fp = 0; int32_t i,j,c; char userpass[8192]; +#ifdef _WIN32 +#ifdef _MSC_VER + printf("*** games for Windows [ Build %s ] ***\n", BUILD_DATE); + const char* arch = is_x64() ? "64-bits" : "32-bits"; + printf(" Built with VC++ %d (%ld) %s\n\n", msver(), _MSC_FULL_VER, arch); +#endif +#endif + + for (i=j=0; argv[0][i]!=0&&j +#include +#ifdef BUILD_GAMESCC +#include "../rogue/cursesd.h" +#else +#include +#endif + +#define SATOSHIDEN ((uint64_t)100000000L) +#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"prices",cmdstr,0,0,0) +extern int64_t Net_change,Betsize; + +int random_tetromino(struct games_state *rs) +{ + rs->seed = _games_rngnext(rs->seed); + return(rs->seed % NUM_TETROMINOS); +} + +int32_t pricesdata(struct games_player *P,void *ptr) +{ + tetris_game *tg = (tetris_game *)ptr; + P->gold = tg->points; + P->dungeonlevel = tg->level; + //fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); + return(0); +} + +void sleep_milli(int milliseconds) +{ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = milliseconds * 1000 * 1000; + nanosleep(&ts, NULL); +} + +struct games_state globalR; +extern char Gametxidstr[]; +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); +uint64_t get_btcusd(); +int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize); + +void *gamesiterate(struct games_state *rs) +{ + bool running = true; uint32_t eventid = 0; int64_t price; + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) + { + initscr(); // initialize curses + cbreak(); // pass key presses to program, but not signals + noecho(); // don't echo key presses to screen + timeout(0); + } + while ( running != 0 ) + { + //running = tg_tick(rs,tg,move); + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) + { + } + if ( rs->guiflag != 0 ) + { +#ifdef STANDALONE + price = get_btcusd(); + //fprintf(stderr,"%llu -> t%u %.4f\n",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); + //issue_games_events(rs,Gametxidstr,eventid,price); + issue_bet(rs,price,Betsize); + eventid++; + doupdate(); + sleep(10); + switch ( getch() ) + { + case '+': Net_change++; break; + case '-': Net_change--; break; + case '0': Net_change = 0; break; + case '$': Betsize = SATOSHIDEN; break; + case '^': Betsize += (Betsize >> 3); break; + case '/': Betsize -= (Betsize >> 3); break; + } + /*if ( (counter++ % 10) == 0 ) + doupdate(); + c = games_readevent(rs); + if ( c <= 0x7f || skipcount == 0x3fff ) + { + if ( skipcount > 0 ) + issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); + if ( c <= 0x7f ) + issue_games_events(rs,Gametxidstr,eventid,c); + if ( tg->level != prevlevel ) + { + flushkeystrokes(rs,0); + prevlevel = tg->level; + } + skipcount = 0; + } else skipcount++;*/ +#endif + } + else + { + if ( rs->replaydone != 0 ) + break; + if ( rs->sleeptime != 0 ) + { + sleep_milli(1); + } + /*if ( skipcount == 0 ) + { + c = games_readevent(rs); + //fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); + if ( (c & 0x4000) == 0x4000 ) + { + skipcount = (c & 0x3fff); + c = 'S'; + } + } + if ( skipcount > 0 ) + skipcount--;*/ + } + eventid++; + } + return(0); +} + +#ifdef STANDALONE +#include +#include "dapps/dappstd.c" +int64_t Net_change,Betsize = SATOSHIDEN; + +char *send_curl(char *url,char *fname) +{ + char *retstr; + retstr = issue_curl(url); + return(retstr); +} + +cJSON *get_urljson(char *url,char *fname) +{ + char *jsonstr; cJSON *json = 0; + if ( (jsonstr= send_curl(url,fname)) != 0 ) + { + //printf("(%s) -> (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + return(json); +} + +////////////////////////////////////////////// +// start of dapp +////////////////////////////////////////////// + +uint64_t get_btcusd() +{ + cJSON *pjson,*bpi,*usd; char str[512]; uint64_t x,newprice,mult,btcusd = 0; + if ( (pjson= get_urljson((char *)"http://api.coindesk.com/v1/bpi/currentprice.json",(char *)"/tmp/oraclefeed.json")) != 0 ) + { + if ( (bpi= jobj(pjson,(char *)"bpi")) != 0 && (usd= jobj(bpi,(char *)"USD")) != 0 ) + { + btcusd = jdouble(usd,(char *)"rate_float") * SATOSHIDEN; + mult = 10000 + Net_change*10; + newprice = (btcusd * mult) / 10000; + x = ((uint64_t)time(NULL) << 32) | ((newprice / 10000) & 0xffffffff); + sprintf(str,"BTC/USD %.4f -> Betsize %.8f (^ / to change) && %.4f Net %.1f%% [+ - to change]\n",dstr(btcusd),dstr(Betsize),dstr(newprice),(double)100*(mult-10000)/10000); + mvaddstr(0, 0, str); + clrtoeol(); + doupdate(); + } + free_json(pjson); + } + return(x); +} + +char *clonestr(char *str) +{ + char *clone; int32_t len; + if ( str == 0 || str[0] == 0 ) + { + printf("warning cloning nullstr.%p\n",str); +#ifdef __APPLE__ + while ( 1 ) sleep(1); +#endif + str = (char *)""; + } + len = strlen(str); + clone = (char *)calloc(1,len+16); + strcpy(clone,str); + return(clone); +} + +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) +{ + static FILE *fp; + char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + rs->buffered[rs->num++] = c; + if ( 1 ) + { + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); + } else return(0); +} + +int32_t issue_bet(struct games_state *rs,int64_t x,int64_t betsize) +{ + char params[512],hexstr[64],*retstr; cJSON *retjson,*resobj; int32_t i,retval = -1; + memset(hexstr,0,sizeof(hexstr)); + for (i=0; i<8; i++) + { + sprintf(&hexstr[i<<1],"%02x",(uint8_t)(x & 0xff)); + x >>= 8; + } + sprintf(params,"[\"bet\",\"17\",\"[%.8f,%%22%s%%22]\"]",dstr(betsize),hexstr); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + //fprintf(stderr,"%s\n",jprint(resobj,0)); + } + free_json(retjson); + } + free(retstr); + } + return(retval); +} + +int prices(int argc, char **argv) +{ + struct games_state *rs = &globalR; + int32_t c,skipcount=0; uint32_t eventid = 0; + memset(rs,0,sizeof(*rs)); + rs->guiflag = 1; + rs->sleeptime = 1; // non-zero to allow refresh() + if ( argc >= 2 && strlen(argv[2]) == 64 ) + { +#ifdef _WIN32 +#ifdef _MSC_VER + rs->origseed = _strtoui64(argv[1], NULL, 10); +#else + rs->origseed = atol(argv[1]); // windows, but not MSVC +#endif // _MSC_VER +#else + rs->origseed = atol(argv[1]); // non-windows +#endif // _WIN32 + rs->seed = rs->origseed; + if ( argc >= 3 ) + { + strcpy(Gametxidstr,argv[2]); + fprintf(stderr,"setplayerdata %s\n",Gametxidstr); + if ( games_setplayerdata(rs,Gametxidstr) < 0 ) + { + fprintf(stderr,"invalid gametxid, or already started\n"); + return(-1); + } + } + } else rs->seed = 777; + gamesiterate(rs); + //gamesbailout(rs); + return 0; +} + +#endif + diff --git a/src/cc/games/prices.cpp b/src/cc/games/prices.cpp new file mode 100644 index 000000000..5c8437e5d --- /dev/null +++ b/src/cc/games/prices.cpp @@ -0,0 +1,281 @@ + +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ + +std::string MYCCLIBNAME = (char *)"prices"; + +#define PRICES_BETPERIOD 3 +UniValue games_rawtxresult(UniValue &result,std::string rawtx,int32_t broadcastflag); +extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; + +#define bstr(x) ((double)((uint32_t)x) / 10000.) + +struct prices_bar +{ + uint64_t open,high,low,close,sum; + int32_t num; +}; + +int32_t prices_barupdate(struct prices_bar *bar,uint64_t pricebits) +{ + uint32_t uprice,timestamp; + timestamp = (uint32_t)(pricebits >> 32); + uprice = (uint32_t)pricebits; + bar->sum += uprice, bar->num++; + if ( bar->open == 0 ) + bar->open = bar->high = bar->low = pricebits; + if ( uprice > (uint32_t)bar->high ) + bar->high = pricebits; + else if ( uprice < (uint32_t)bar->low ) + bar->low = pricebits; + bar->close = pricebits; + return(0); +} + +int64_t prices_bardist(struct prices_bar *bar,uint32_t aveprice,uint64_t pricebits) +{ + int64_t a,dist = 0; + if ( aveprice != 0 ) + { + a = (pricebits & 0xffffffff); + dist = (a - aveprice); + dist *= dist; + //fprintf(stderr,"dist.%lld (u %u - ave %u) %d\n",(long long)dist,uprice,aveprice,uprice-aveprice); + } + return(dist); +} + +void prices_bardisp(struct prices_bar *bar) +{ + if ( bar->num == 0 ) + fprintf(stderr,"BAR null\n"); + else fprintf(stderr,"BAR ave %.4f (O %.4f, H %.4f, L %.4f, C %.4f)\n",bstr(bar->sum/bar->num),bstr(bar->open),bstr(bar->high),bstr(bar->low),bstr(bar->close)); +} + +int64_t prices_blockinfo(int32_t height,char *acaddr) +{ + std::vector vopret; CBlockIndex *pindex; CBlock block; CTransaction tx,vintx; uint64_t pricebits; char destaddr[64]; uint32_t aveprice=0,timestamp,uprice; uint256 hashBlock; int64_t dist,mindist=(1LL<<60),prizefund = 0; int32_t mini=-1,i,n,vini,numvouts,iter; struct prices_bar refbar; + if ( (pindex= komodo_chainactive(height)) != 0 ) + { + if ( komodo_blockload(block,pindex) == 0 ) + { + n = block.vtx.size(); + vini = 0; + memset(&refbar,0,sizeof(refbar)); + for (iter=0; iter<2; iter++) + { + for (i=0; i= vintx.vout.size() || Getscriptaddress(destaddr,vintx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ) + continue; + else if ( (numvouts= tx.vout.size()) > 1 && tx.vout[numvouts-1].scriptPubKey[0] == 0x6a ) + { + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); + if ( vopret.size() == 8 ) + { + E_UNMARSHAL(vopret,ss >> pricebits); + timestamp = (uint32_t)(pricebits >> 32); + uprice = (uint32_t)pricebits; + if ( iter == 0 ) + { + prizefund += tx.vout[0].nValue; + if ( strcmp(acaddr,destaddr) == 0 ) + { + //fprintf(stderr,"REF "); + prices_barupdate(&refbar,pricebits); + } + } + else if ( strcmp(acaddr,destaddr) != 0 ) + { + dist = prices_bardist(&refbar,aveprice,pricebits); + if ( dist < mindist ) + { + mindist = dist; + mini = i; + } + fprintf(stderr,"mini.%d i.%d %.8f t%u %.4f v.%d %s lag.%d i.%d dist.%lld\n",mini,i,(double)tx.vout[0].nValue/COIN,timestamp,(double)uprice/10000,numvouts,destaddr,(int32_t)(pindex->nTime-timestamp),iter,(long long)dist); + } + } else return(-3); + } + } + if ( iter == 0 ) + { + prices_bardisp(&refbar); + if ( refbar.num != 0 ) + aveprice = (uint32_t)refbar.sum / refbar.num; + } + } + return(prizefund); + } else return(-2); + } else return(-1); +} + +UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + UniValue result(UniValue::VOBJ); char acaddr[64]; CPubKey acpk,mypk,gamespk; int64_t prizefund = 0; int32_t height,nextheight = komodo_nextheight(); + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error"," no -ac_pubkey for price reference")); + return(result); + } + mypk = pubkey2pk(Mypubkey()); + gamespk = GetUnspendable(cp,0); + acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); + Getscriptaddress(acaddr,CScript() << ParseHex(HexStr(acpk)) << OP_CHECKSIG); + if ( params != 0 && cJSON_GetArraySize(params) == 1 ) + { + height = juint(jitem(params,0),0); + result.push_back(Pair("height",(int64_t)height)); + if ( (prizefund= prices_blockinfo(height,acaddr)) < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("errorcode",prizefund)); + result.push_back(Pair("error","blockinfo error")); + } + else + { + // display bets + if ( height <= nextheight-PRICES_BETPERIOD ) + { + // settle bets by first nonzero reference bar + } + result.push_back(Pair("prizefund",ValueFromAmount(prizefund))); + result.push_back(Pair("result","success")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse")); + } + return(result); +} + +UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; uint64_t price; CPubKey gamespk,mypk,acpk; + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] == 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error"," no -ac_pubkey for price reference")); + return(result); + } + mypk = pubkey2pk(Mypubkey()); + gamespk = GetUnspendable(cp,0); + acpk = buf2pk(ASSETCHAINS_OVERRIDE_PUBKEY33); + if ( params != 0 && cJSON_GetArraySize(params) == 2 ) + { + amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; + if ( cclib_parsehash((uint8_t *)&price,jitem(params,1),8) < 0 ) + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parsehash")); + return(result); + } + if ( mypk == acpk ) + { + amount = 0; // i am the reference price feed + //fprintf(stderr,"i am the reference\n"); + } + //fprintf(stderr,"amount %llu price %llx\n",(long long)amount,(long long)price); + if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) + { + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,CScript() << OP_RETURN << price); + return(games_rawtxresult(result,rawtx,1)); + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough funds")); + } + } + else + { + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse")); + } + return(result); +} + +void prices_update(uint32_t timestamp,uint32_t uprice,int32_t ismine) +{ + //fprintf(stderr,"%s t%u %.4f %16llx\n",ismine!=0?"mine":"ext ",timestamp,(double)uprice/10000,(long long)((uint64_t)timestamp<<32) | uprice); +} + +// game specific code for daemon +void games_packitemstr(char *packitemstr,struct games_packitem *item) +{ + strcpy(packitemstr,""); +} + +int64_t games_cashout(struct games_player *P) +{ + int32_t dungeonlevel = P->dungeonlevel; int64_t mult=1000,cashout = 0; + cashout = (uint64_t)P->gold * mult * dungeonlevel * dungeonlevel; + return(cashout); +} + +void pricesplayerjson(UniValue &obj,struct games_player *P) +{ + obj.push_back(Pair("packsize",(int64_t)P->packsize)); + obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); + obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff))); + obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16))); + obj.push_back(Pair("level",(int64_t)P->level)); + obj.push_back(Pair("experience",(int64_t)P->experience)); + obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel)); +} + +int32_t disp_gamesplayer(char *str,struct games_player *P) +{ + str[0] = 0; + //if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) + // return(-1); + sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); + return(0); +} + +int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) +{ + uint256 gametxid; int32_t i,len; char str[67]; int64_t price; uint32_t eventid = 0; + if ( (len= payload.size()) > 36 ) + { + len -= 36; + for (i=0; i<32; i++) + ((uint8_t *)&gametxid)[i] = payload[len+i]; + eventid = (uint32_t)payload[len+32]; + eventid |= (uint32_t)payload[len+33] << 8; + eventid |= (uint32_t)payload[len+34] << 16; + eventid |= (uint32_t)payload[len+35] << 24; + for (i=0; i> 32),(uint32_t)(price & 0xffffffff),pk == pubkey2pk(Mypubkey())); + //fprintf(stderr,"%llu -> t%u %.4f ",(long long)price,(uint32_t)(price >> 32),(double)(price & 0xffffffff)/10000); + //fprintf(stderr," got payload, from %s %s/e%d\n",pubkey33_str(str,(uint8_t *)&pk),gametxid.GetHex().c_str(),eventid); + return(0); + } else return(-1); +} + +bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +{ + return(true); +} + diff --git a/src/cc/games/prices.h b/src/cc/games/prices.h new file mode 100644 index 000000000..ae1c46821 --- /dev/null +++ b/src/cc/games/prices.h @@ -0,0 +1,208 @@ + +#ifndef H_PRICES_H +#define H_PRICES_H + +/***************************************************************************/ +/** https://github.com/brenns10/tetris + @file main.c + @author Stephen Brennan + @date Created Wednesday, 10 June 2015 + @brief Main program for tetris. + @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised + BSD License. See LICENSE.txt for details. + *******************************************************************************/ + +/* + Convert a tetromino type to its corresponding cell. + */ +#define TYPE_TO_CELL(x) ((x)+1) + +/* + Strings for how you would print a tetris board. + */ +#define TC_EMPTY_STR " " +#define TC_BLOCK_STR "\u2588" + +/* + Questions about a tetris cell. + */ +#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) +#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) + +/* + How many cells in a tetromino? + */ +#define TETRIS 4 +/* + How many tetrominos? + */ +#define NUM_TETROMINOS 7 +/* + How many orientations of a tetromino? + */ +#define NUM_ORIENTATIONS 4 + +/* + Level constants. + */ +#define MAX_LEVEL 19 +#define LINES_PER_LEVEL 10 + +/* + A "cell" is a 1x1 block within a tetris board. + */ +typedef enum { + TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ +} tetris_cell; + +/* + A "type" is a type/shape of a tetromino. Not including orientation. + */ +typedef enum { + TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z +} tetris_type; + +/* + A row,column pair. Negative numbers allowed, because we need them for + offsets. + */ +typedef struct { + int row; + int col; +} tetris_location; + +/* + A "block" is a struct that contains information about a tetromino. + Specifically, what type it is, what orientation it has, and where it is. + */ +typedef struct { + int typ; + int ori; + tetris_location loc; +} tetris_block; + +/* + All possible moves to give as input to the game. + */ +typedef enum { + TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE +} tetris_move; + +/* + A game object! + */ +typedef struct { + /* + Game board stuff: + */ + int rows; + int cols; + /* + Scoring information: + */ + int points; + int level; + /* + Falling block is the one currently going down. Next block is the one that + will be falling after this one. Stored is the block that you can swap out. + */ + tetris_block falling; + tetris_block next; + tetris_block stored; + /* + Number of game ticks until the block will move down. + */ + int ticks_till_gravity; + /* + Number of lines until you advance to the next level. + */ + int lines_remaining; + char board[]; +} tetris_game; + +/* + This array stores all necessary information about the cells that are filled by + each tetromino. The first index is the type of the tetromino (i.e. shape, + e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final + array contains 4 tetris_location objects, each mapping to an offset from a + point on the upper left that is the tetromino "origin". + */ +extern const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; + +/* + This array tells you how many ticks per gravity by level. Decreases as level + increases, to add difficulty. + */ +extern const int GRAVITY_LEVEL[MAX_LEVEL+1]; + +// Data structure manipulation. +void tg_init(tetris_game *obj, int rows, int cols); +tetris_game *tg_create(struct games_state *rs,int rows, int cols); +void tg_destroy(tetris_game *obj); +void tg_delete(tetris_game *obj); +tetris_game *tg_load(FILE *f); +void tg_save(tetris_game *obj, FILE *f); + +// Public methods not related to memory: +char tg_get(tetris_game *obj, int row, int col); +bool tg_check(tetris_game *obj, int row, int col); +bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move); +void tg_print(tetris_game *obj, FILE *f); + +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ +#define GAMENAME "prices" // name of executable +#define GAMEMAIN prices // main program of game +#define GAMEPLAYERJSON pricesplayerjson // displays game specific json +#define GAMEDATA pricesdata // extracts data from game specific variables into games_state +#define CHAINNAME "PRICES" // -ac_name= +typedef uint64_t gamesevent; // can be 8, 16, 32, or 64 bits + +#define MAXPACK 23 +struct games_packitem +{ + int32_t type,launch,count,which,hplus,dplus,arm,flags,group; + char damage[8],hurldmg[8]; +}; + +struct games_player +{ + int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet; + struct games_packitem gamespack[MAXPACK]; +}; + +struct games_state +{ + uint64_t seed,origseed; + char *keystrokeshex; + uint32_t needflush,replaydone; + int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; + FILE *logfp; + struct games_player P; + gamesevent buffered[5000],*keystrokes; + uint8_t playerdata[8192]; +}; +extern struct games_state globalR; +void *gamesiterate(struct games_state *rs); +int32_t flushkeystrokes(struct games_state *rs,int32_t waitflag); + +void games_packitemstr(char *packitemstr,struct games_packitem *item); +uint64_t _games_rngnext(uint64_t initseed); +int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); +gamesevent games_revendian(gamesevent revx); +int32_t disp_gamesplayer(char *str,struct games_player *P); + +#endif + diff --git a/src/cc/games/tetris.c b/src/cc/games/tetris.c new file mode 100644 index 000000000..8e7642837 --- /dev/null +++ b/src/cc/games/tetris.c @@ -0,0 +1,904 @@ + +#include "tetris.h" + +/* + In order to port a game into gamesCC, the RNG needs to be seeded with the gametxid seed, also events needs to be broadcast using issue_games_events. Also the game engine needs to be daemonized, preferably by putting all globals into a single data structure. + + also, the standalone game needs to support argv of seed gametxid, along with replay args + */ + +int random_tetromino(struct games_state *rs) +{ + rs->seed = _games_rngnext(rs->seed); + return(rs->seed % NUM_TETROMINOS); +} + +int32_t tetrisdata(struct games_player *P,void *ptr) +{ + tetris_game *tg = (tetris_game *)ptr; + P->gold = tg->points; + P->dungeonlevel = tg->level; + //fprintf(stderr,"score.%d level.%d\n",tg->points,tg->level); + return(0); +} + +/***************************************************************************/ +/** https://github.com/brenns10/tetris + @file main.c + @author Stephen Brennan + @date Created Wednesday, 10 June 2015 + @brief Main program for tetris. + @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised + BSD License. See LICENSE.txt for details. + *******************************************************************************/ + + +#include // for FILE +#include // for bool +#include +#include +#include +#include +#include +#include + +#ifdef BUILD_GAMESCC +#include "../rogue/cursesd.h" +#else +#include +#endif + + +#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) +#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) + +/******************************************************************************* + Array Definitions + *******************************************************************************/ + +const tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = +{ + // I + {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, + {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, + {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, + {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, + // J + {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, + {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, + // L + {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, + {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, + // O + {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, + {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, + // S + {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, + {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, + {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, + // T + {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, + {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, + // Z + {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, + {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, + {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, + {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, +}; + +const int GRAVITY_LEVEL[MAX_LEVEL+1] = { + // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, + //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 +}; + +/******************************************************************************* + Helper Functions for Blocks + *******************************************************************************/ + +void sleep_milli(int milliseconds) +{ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = milliseconds * 1000 * 1000; + nanosleep(&ts, NULL); +} + +/* + Return the block at the given row and column. + */ +char tg_get(tetris_game *obj, int row, int column) +{ + return obj->board[obj->cols * row + column]; +} + +/* + Set the block at the given row and column. + */ +static void tg_set(tetris_game *obj, int row, int column, char value) +{ + obj->board[obj->cols * row + column] = value; +} + +/* + Check whether a row and column are in bounds. + */ +bool tg_check(tetris_game *obj, int row, int col) +{ + return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; +} + +/* + Place a block onto the board. + */ +static void tg_put(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, + TYPE_TO_CELL(block.typ)); + } +} + +/* + Clear a block out of the board. + */ +static void tg_remove(tetris_game *obj, tetris_block block) +{ + int i; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); + } +} + +/* + Check if a block can be placed on the board. + */ +static bool tg_fits(tetris_game *obj, tetris_block block) +{ + int i, r, c; + for (i = 0; i < TETRIS; i++) { + tetris_location cell = TETROMINOS[block.typ][block.ori][i]; + r = block.loc.row + cell.row; + c = block.loc.col + cell.col; + if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { + return false; + } + } + return true; +} + +/* + Create a new falling block and populate the next falling block with a random + one. + */ +static void tg_new_falling(struct games_state *rs,tetris_game *obj) +{ + // Put in a new falling tetromino. + obj->falling = obj->next; + obj->next.typ = random_tetromino(rs); + obj->next.ori = 0; + obj->next.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; +} + +/******************************************************************************* + Game Turn Helpers + *******************************************************************************/ + +/* + Tick gravity, and move the block down if gravity should act. + */ +static void tg_do_gravity_tick(struct games_state *rs,tetris_game *obj) +{ + obj->ticks_till_gravity--; + if (obj->ticks_till_gravity <= 0) { + tg_remove(obj, obj->falling); + obj->falling.loc.row++; + if (tg_fits(obj, obj->falling)) { + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + } else { + obj->falling.loc.row--; + tg_put(obj, obj->falling); + + tg_new_falling(rs,obj); + } + tg_put(obj, obj->falling); + } +} + +/* + Move the falling tetris block left (-1) or right (+1). + */ +static void tg_move(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + obj->falling.loc.col += direction; + if (!tg_fits(obj, obj->falling)) { + obj->falling.loc.col -= direction; + } + tg_put(obj, obj->falling); +} + +/* + Send the falling tetris block to the bottom. + */ +static void tg_down(struct games_state *rs,tetris_game *obj) +{ + tg_remove(obj, obj->falling); + while (tg_fits(obj, obj->falling)) { + obj->falling.loc.row++; + } + obj->falling.loc.row--; + tg_put(obj, obj->falling); + tg_new_falling(rs,obj); +} + +/* + Rotate the falling block in either direction (+/-1). + */ +static void tg_rotate(tetris_game *obj, int direction) +{ + tg_remove(obj, obj->falling); + + while (true) { + obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; + + // If the new orientation fits, we're done. + if (tg_fits(obj, obj->falling)) + break; + + // Otherwise, try moving left to make it fit. + obj->falling.loc.col--; + if (tg_fits(obj, obj->falling)) + break; + + // Finally, try moving right to make it fit. + obj->falling.loc.col += 2; + if (tg_fits(obj, obj->falling)) + break; + + // Put it back in its original location and try the next orientation. + obj->falling.loc.col--; + // Worst case, we come back to the original orientation and it fits, so this + // loop will terminate. + } + + tg_put(obj, obj->falling); +} + +/* + Swap the falling block with the block in the hold buffer. + */ +static void tg_hold(struct games_state *rs,tetris_game *obj) +{ + tg_remove(obj, obj->falling); + if (obj->stored.typ == -1) { + obj->stored = obj->falling; + tg_new_falling(rs,obj); + } else { + int typ = obj->falling.typ, ori = obj->falling.ori; + obj->falling.typ = obj->stored.typ; + obj->falling.ori = obj->stored.ori; + obj->stored.typ = typ; + obj->stored.ori = ori; + while (!tg_fits(obj, obj->falling)) { + obj->falling.loc.row--; + if (tg_fits(obj, obj->falling)) { + break; + } + obj->falling.loc.col--; + if (tg_fits(obj, obj->falling)) { + break; + } + obj->falling.loc.col += 2; + } + } + tg_put(obj, obj->falling); +} + +/* + Perform the action specified by the move. + */ +static void tg_handle_move(struct games_state *rs,tetris_game *obj, tetris_move move) +{ + switch (move) { + case TM_LEFT: + //fprintf(stderr,"LEFT "); + tg_move(obj, -1); + break; + case TM_RIGHT: + //fprintf(stderr,"RIGHT "); + tg_move(obj, 1); + break; + case TM_DROP: + tg_down(rs,obj); + break; + case TM_CLOCK: + tg_rotate(obj, 1); + break; + case TM_COUNTER: + tg_rotate(obj, -1); + break; + case TM_HOLD: + tg_hold(rs,obj); + break; + default: + // pass + break; + } +} + +/* + Return true if line i is full. + */ +static bool tg_line_full(tetris_game *obj, int i) +{ + int j; + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) + return false; + } + return true; +} + +/* + Shift every row above r down one. + */ +static void tg_shift_lines(tetris_game *obj, int r) +{ + int i, j; + for (i = r-1; i >= 0; i--) { + for (j = 0; j < obj->cols; j++) { + tg_set(obj, i+1, j, tg_get(obj, i, j)); + tg_set(obj, i, j, TC_EMPTY); + } + } +} + +/* + Find rows that are filled, remove them, shift, and return the number of + cleared rows. + */ +static int tg_check_lines(tetris_game *obj) +{ + int i, nlines = 0; + tg_remove(obj, obj->falling); // don't want to mess up falling block + + for (i = obj->rows-1; i >= 0; i--) { + if (tg_line_full(obj, i)) { + tg_shift_lines(obj, i); + i++; // do this line over again since they're shifted + nlines++; + } + } + + tg_put(obj, obj->falling); // replace + return nlines; +} + +/* + Adjust the score for the game, given how many lines were just cleared. + */ +static void tg_adjust_score(tetris_game *obj, int lines_cleared) +{ + static int line_multiplier[] = {0, 40, 100, 300, 1200}; + obj->points += line_multiplier[lines_cleared] * (obj->level + 1); + if (lines_cleared >= obj->lines_remaining) { + obj->level = MIN(MAX_LEVEL, obj->level + 1); + lines_cleared -= obj->lines_remaining; + obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; + } else { + obj->lines_remaining -= lines_cleared; + } +} + +/* + Return true if the game is over. + */ +static bool tg_game_over(tetris_game *obj) +{ + int i, j; + bool over = false; + tg_remove(obj, obj->falling); + for (i = 0; i < 2; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + over = true; + } + } + } + tg_put(obj, obj->falling); + return over; +} + +/******************************************************************************* + Main Public Functions + *******************************************************************************/ + +/* + Do a single game tick: process gravity, user input, and score. Return true if + the game is still running, false if it is over. + */ +bool tg_tick(struct games_state *rs,tetris_game *obj, tetris_move move) +{ + int lines_cleared; + // Handle gravity. + tg_do_gravity_tick(rs,obj); + + // Handle input. + tg_handle_move(rs,obj, move); + + // Check for cleared lines + lines_cleared = tg_check_lines(obj); + + tg_adjust_score(obj, lines_cleared); + + // Return whether the game will continue (NOT whether it's over) + return !tg_game_over(obj); +} + +void tg_init(struct games_state *rs,tetris_game *obj, int rows, int cols) +{ + // Initialization logic + obj->rows = rows; + obj->cols = cols; + //obj->board = (char *)malloc(rows * cols); + memset(obj->board, TC_EMPTY, rows * cols); + obj->points = 0; + obj->level = 0; + obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; + obj->lines_remaining = LINES_PER_LEVEL; + //srand(time(NULL)); + tg_new_falling(rs,obj); + tg_new_falling(rs,obj); + obj->stored.typ = -1; + obj->stored.ori = 0; + obj->stored.loc.row = 0; + obj->next.loc.col = obj->cols/2 - 2; + //printf("%d", obj->falling.loc.col); +} + +tetris_game *tg_create(struct games_state *rs,int rows, int cols) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game) + rows*cols); + tg_init(rs,obj, rows, cols); + return obj; +} + +/*void tg_destroy(tetris_game *obj) +{ + // Cleanup logic + free(obj->board); +}*/ + +void tg_delete(tetris_game *obj) { + //tg_destroy(obj); + free(obj); +} + +/* + Load a game from a file. + +tetris_game *tg_load(FILE *f) +{ + tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); + if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) + { + fprintf(stderr,"read game error\n"); + free(obj); + obj = 0; + } + else + { + obj->board = (char *)malloc(obj->rows * obj->cols); + if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + { + fprintf(stderr,"fread error\n"); + free(obj->board); + free(obj); + obj = 0; + } + } + return obj; +}*/ + +/* + Save a game to a file. + +void tg_save(tetris_game *obj, FILE *f) +{ + if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) + fprintf(stderr,"error writing tetrisgame\n"); + else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + fprintf(stderr,"error writing board\n"); +}*/ + +/* + Print a game board to a file. Really just for early debugging. + */ +void tg_print(tetris_game *obj, FILE *f) { + int i, j; + for (i = 0; i < obj->rows; i++) { + for (j = 0; j < obj->cols; j++) { + if (TC_IS_EMPTY(tg_get(obj, i, j))) { + fputs(TC_EMPTY_STR, f); + } else { + fputs(TC_BLOCK_STR, f); + } + } + fputc('\n', f); + } +} + +/* + 2 columns per cell makes the game much nicer. + */ +#define COLS_PER_CELL 2 +/* + Macro to print a cell of a specific type to a window. + */ +#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ +waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) +#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') + +/* + Print the tetris board onto the ncurses window. + */ +void display_board(WINDOW *w, tetris_game *obj) +{ + int i, j; + box(w, 0, 0); + for (i = 0; i < obj->rows; i++) { + wmove(w, 1 + i, 1); + for (j = 0; j < obj->cols; j++) { + if (TC_IS_FILLED(tg_get(obj, i, j))) { + ADD_BLOCK(w,tg_get(obj, i, j)); + } else { + ADD_EMPTY(w); + } + } + } + wnoutrefresh(w); +} + +/* + Display a tetris piece in a dedicated window. + */ +void display_piece(WINDOW *w, tetris_block block) +{ + int b; + tetris_location c; + wclear(w); + box(w, 0, 0); + if (block.typ == -1) { + wnoutrefresh(w); + return; + } + for (b = 0; b < TETRIS; b++) { + c = TETROMINOS[block.typ][block.ori][b]; + wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); + ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); + } + wnoutrefresh(w); +} + +/* + Display score information in a dedicated window. + */ +void display_score(WINDOW *w, tetris_game *tg) +{ + wclear(w); + box(w, 0, 0); + wprintw(w, (char *)"Score\n%d\n", tg->points); + wprintw(w, (char *)"Level\n%d\n", tg->level); + wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining); + wnoutrefresh(w); +} + +/* + Save and exit the game. + +void save(tetris_game *game, WINDOW *w) +{ + FILE *f; + + wclear(w); + box(w, 0, 0); // return the border + wmove(w, 1, 1); + wprintw(w, (char *)"Save and exit? [Y/n] "); + wrefresh(w); + timeout(-1); + if (getch() == 'n') { + timeout(0); + return; + } + f = fopen("tetris.save", "w"); + tg_save(game, f); + fclose(f); + tg_delete(game); + endwin(); + fprintf(stderr,"Game saved to \"tetris.save\".\n"); + fprintf(stderr,"Resume by passing the filename as an argument to this program.\n"); + exit(EXIT_SUCCESS); +}*/ + +/* + Do the NCURSES initialization steps for color blocks. + */ +void init_colors(void) +{ + start_color(); + //init_color(COLOR_ORANGE, 1000, 647, 0); + init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); + init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); + init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); + init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); + init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); + init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); + init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); +} + +struct games_state globalR; +extern char Gametxidstr[]; +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c); +gamesevent games_readevent(struct games_state *rs); + +void *gamesiterate(struct games_state *rs) +{ + uint32_t counter = 0; bool running = true; tetris_move move = TM_NONE; + gamesevent c; uint16_t skipcount=0; int32_t prevlevel; uint32_t eventid = 0; tetris_game *tg; + WINDOW *board, *next, *hold, *score; + if ( rs->guiflag != 0 || rs->sleeptime != 0 ) + { + // NCURSES initialization: + initscr(); // initialize curses + cbreak(); // pass key presses to program, but not signals + noecho(); // don't echo key presses to screen + keypad(stdscr, TRUE); // allow arrow keys + timeout(0); // no blocking on getch() + curs_set(0); // set the cursor to invisible + init_colors(); // setup tetris colors + } + tg = tg_create(rs,22, 10); + prevlevel = tg->level; + // Create windows for each section of the interface. + board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); + next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); + hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); + score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); + while ( running != 0 ) + { + running = tg_tick(rs,tg,move); + if ( 1 && (rs->guiflag != 0 || rs->sleeptime != 0) ) + { + display_board(board,tg); + display_piece(next,tg->next); + display_piece(hold,tg->stored); + display_score(score,tg); + } + if ( rs->guiflag != 0 ) + { +#ifdef STANDALONE + sleep_milli(15); + if ( (counter++ % 10) == 0 ) + doupdate(); + c = games_readevent(rs); + if ( c <= 0x7f || skipcount == 0x3fff ) + { + if ( skipcount > 0 ) + issue_games_events(rs,Gametxidstr,eventid-skipcount,skipcount | 0x4000); + if ( c <= 0x7f ) + issue_games_events(rs,Gametxidstr,eventid,c); + if ( tg->level != prevlevel ) + { + flushkeystrokes(rs,0); + prevlevel = tg->level; + } + skipcount = 0; + } else skipcount++; +#endif + } + else + { + if ( rs->replaydone != 0 ) + break; + if ( rs->sleeptime != 0 ) + { + sleep_milli(1); + if ( (counter++ % 20) == 0 ) + doupdate(); + } + if ( skipcount == 0 ) + { + c = games_readevent(rs); + //fprintf(stderr,"%04x score.%d level.%d\n",c,tg->points,tg->level); + if ( (c & 0x4000) == 0x4000 ) + { + skipcount = (c & 0x3fff); + c = 'S'; + } + } + if ( skipcount > 0 ) + skipcount--; + } + eventid++; + switch ( c ) + { + case 'h': + move = TM_LEFT; + break; + case 'l': + move = TM_RIGHT; + break; + case 'k': + move = TM_CLOCK; + break; + case 'j': + move = TM_DROP; + break; + case 'q': + running = false; + move = TM_NONE; + break; + /*case 'p': + wclear(board); + box(board, 0, 0); + wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); + wprintw(board, "PAUSED"); + wrefresh(board); + timeout(-1); + getch(); + timeout(0); + move = TM_NONE; + break; + case 's': + save(tg, board); + move = TM_NONE; + break;*/ + case ' ': + move = TM_HOLD; + break; + default: + move = TM_NONE; + } + } + return(tg); +} + +#ifdef STANDALONE +/* + Main tetris game! + */ +#include "dapps/dappstd.c" + + +char *clonestr(char *str) +{ + char *clone; int32_t len; + if ( str == 0 || str[0] == 0 ) + { + printf("warning cloning nullstr.%p\n",str); +#ifdef __APPLE__ + while ( 1 ) sleep(1); +#endif + str = (char *)""; + } + len = strlen(str); + clone = (char *)calloc(1,len+16); + strcpy(clone,str); + return(clone); +} + +int32_t issue_games_events(struct games_state *rs,char *gametxidstr,uint32_t eventid,gamesevent c) +{ + static FILE *fp; + char params[512],*retstr; cJSON *retjson,*resobj; int32_t retval = -1; + if ( fp == 0 ) + fp = fopen("events.log","wb"); + rs->buffered[rs->num++] = c; + if ( 0 ) + { + if ( sizeof(c) == 1 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%02x%%22,%%22%s%%22,%u]\"]",(uint8_t)c&0xff,gametxidstr,eventid); + else if ( sizeof(c) == 2 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%04x%%22,%%22%s%%22,%u]\"]",(uint16_t)c&0xffff,gametxidstr,eventid); + else if ( sizeof(c) == 4 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",(uint32_t)c&0xffffffff,gametxidstr,eventid); + else if ( sizeof(c) == 8 ) + sprintf(params,"[\"events\",\"17\",\"[%%22%016llx%%22,%%22%s%%22,%u]\"]",(long long)c,gametxidstr,eventid); + if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) + { + if ( (retjson= cJSON_Parse(retstr)) != 0 ) + { + if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) + { + retval = 0; + if ( fp != 0 ) + { + fprintf(fp,"%s\n",jprint(resobj,0)); + fflush(fp); + } + } + free_json(retjson); + } else fprintf(fp,"error parsing %s\n",retstr); + free(retstr); + } else fprintf(fp,"error issuing method %s\n",params); + return(retval); + } else return(0); +} + +int tetris(int argc, char **argv) +{ + struct games_state *rs = &globalR; + int32_t c,skipcount=0; uint32_t eventid = 0; tetris_game *tg = 0; + memset(rs,0,sizeof(*rs)); + rs->guiflag = 1; + rs->sleeptime = 1; // non-zero to allow refresh() + if ( argc >= 2 && strlen(argv[2]) == 64 ) + { +#ifdef _WIN32 +#ifdef _MSC_VER + rs->origseed = _strtoui64(argv[1], NULL, 10); +#else + rs->origseed = atol(argv[1]); // windows, but not MSVC +#endif // _MSC_VER +#else + rs->origseed = atol(argv[1]); // non-windows +#endif // _WIN32 + rs->seed = rs->origseed; + if ( argc >= 3 ) + { + strcpy(Gametxidstr,argv[2]); + fprintf(stderr,"setplayerdata %s\n",Gametxidstr); + if ( games_setplayerdata(rs,Gametxidstr) < 0 ) + { + fprintf(stderr,"invalid gametxid, or already started\n"); + return(-1); + } + } + } else rs->seed = 777; + + /* Load file if given a filename. + if (argc >= 2) { + FILE *f = fopen(argv[1], "r"); + if (f == NULL) { + perror("tetris"); + exit(EXIT_FAILURE); + } + tg = tg_load(f); + fclose(f); + } else { + // Otherwise create new game. + tg = tg_create(rs,22, 10); + }*/ + + // Game loop + tg = (tetris_game *)gamesiterate(rs); + gamesbailout(rs); + // Deinitialize NCurses + wclear(stdscr); + endwin(); + // Output ending message. + printf("Game over!\n"); + printf("You finished with %d points on level %d.\n", tg->points, tg->level); + + // Deinitialize Tetris + tg_delete(tg); + return 0; +} + +#endif + diff --git a/src/cc/games/tetris.cpp b/src/cc/games/tetris.cpp new file mode 100644 index 000000000..cd609154d --- /dev/null +++ b/src/cc/games/tetris.cpp @@ -0,0 +1,87 @@ + +/****************************************************************************** + * 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. * + * * + ******************************************************************************/ + +std::string MYCCLIBNAME = (char *)"gamescc"; + +// game specific code for daemon +void games_packitemstr(char *packitemstr,struct games_packitem *item) +{ + strcpy(packitemstr,""); +} + +int64_t games_cashout(struct games_player *P) +{ + int32_t dungeonlevel = P->dungeonlevel; int64_t mult=10000,cashout = 0; + cashout = (uint64_t)P->gold * mult; + return(cashout); +} + +void tetrisplayerjson(UniValue &obj,struct games_player *P) +{ + obj.push_back(Pair("packsize",(int64_t)P->packsize)); + obj.push_back(Pair("hitpoints",(int64_t)P->hitpoints)); + obj.push_back(Pair("strength",(int64_t)(P->strength&0xffff))); + obj.push_back(Pair("maxstrength",(int64_t)(P->strength>>16))); + obj.push_back(Pair("level",(int64_t)P->level)); + obj.push_back(Pair("experience",(int64_t)P->experience)); + obj.push_back(Pair("dungeonlevel",(int64_t)P->dungeonlevel)); +} + +int32_t disp_gamesplayer(char *str,struct games_player *P) +{ + str[0] = 0; + //if ( P->gold <= 0 )//|| P->hitpoints <= 0 || (P->strength&0xffff) <= 0 || P->level <= 0 || P->experience <= 0 || P->dungeonlevel <= 0 ) + // return(-1); + sprintf(str," <- playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",P->gold,P->hitpoints,P->strength&0xffff,P->strength>>16,P->level,P->experience,P->dungeonlevel); + return(0); +} + +int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) +{ + uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; + if ( (len= payload.size()) > 36 ) + { + len -= 36; + for (i=0; i<32; i++) + ((uint8_t *)&gametxid)[i] = payload[len+i]; + eventid = (uint32_t)payload[len+32]; + eventid |= (uint32_t)payload[len+33] << 8; + eventid |= (uint32_t)payload[len+34] << 16; + eventid |= (uint32_t)payload[len+35] << 24; + //for (i=0; i> 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]); +} + +gamesevent games_revendian(gamesevent revx) +{ + int32_t i; gamesevent x = 0; + //fprintf(stderr,"%04x -> ",revx); + for (i=0; iguiflag == 0 ) + { + static uint32_t counter; + if ( rs->ind < rs->numkeys ) + { + ch = rs->keystrokes[rs->ind++]; + if ( 0 ) + { + static FILE *fp; static int32_t counter; + if ( fp == 0 ) + fp = fopen("log","wb"); + if ( fp != 0 ) + { + fprintf(fp,"%d: (%c) seed.%llu\n",counter,c,(long long)rs->origseed); + fflush(fp); + counter++; + } + } + return(ch); + } + if ( rs->replaydone != 0 && counter++ < 3 ) + fprintf(stderr,"replay finished but readchar called\n"); + rs->replaydone = (uint32_t)time(NULL); + return(0); + } + if ( rs == 0 || rs->guiflag != 0 ) + { + c = getch(); + switch ( c ) + { + case KEY_LEFT: + c = 'h'; + break; + case KEY_RIGHT: + c = 'l'; + break; + case KEY_UP: + c = 'k'; + break; + case KEY_DOWN: + c = 'j'; + break; + } + ch = c; + if (ch == 3) + { + //_quit(); + return(27); + } + } else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs); + return(ch); +} + +int32_t games_replay2(uint8_t *newdata,uint64_t seed,gamesevent *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) +{ + struct games_state *rs; FILE *fp; int32_t i,n; void *ptr; + rs = (struct games_state *)calloc(1,sizeof(*rs)); + rs->seed = rs->origseed = seed; + rs->keystrokes = keystrokes; + rs->numkeys = num; + rs->sleeptime = sleepmillis * 1000; + if ( player != 0 ) + { + rs->P = *player; + rs->restoring = 1; + if ( rs->P.packsize > MAXPACK ) + rs->P.packsize = MAXPACK; + } + globalR = *rs; + uint32_t starttime = (uint32_t)time(NULL); + ptr = gamesiterate(rs); + if ( 0 ) + { + fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime); + sleep(2); + starttime = (uint32_t)time(NULL); + for (i=0; i<10000; i++) + { + memset(rs,0,sizeof(*rs)); + rs->seed = rs->origseed = seed; + rs->keystrokes = keystrokes; + rs->numkeys = num; + rs->sleeptime = 0; + gamesiterate(rs); + } + fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL)-starttime); + sleep(3); + } + // extract playerdata + + /*if ( (fp= fopen("checkfile","wb")) != 0 ) + { + //save_file(rs,fp,0); + if ( newdata != 0 && rs->playersize > 0 ) + memcpy(newdata,rs->playerdata,rs->playersize); + }*/ + if ( ptr != 0 ) + { + // extract data from ptr + if ( GAMEDATA(&rs->P,ptr) < 0 ) + memset(&rs->P,0,sizeof(rs->P)); + else + { + rs->playersize = sizeof(rs->P); + if ( newdata != 0 ) + memcpy(newdata,&rs->P,rs->playersize); + } + free(ptr); + } + n = rs->playersize; + //fprintf(stderr,"gold.%d\n",rs->P.gold); sleep(3); + free(rs); + return(n); +} #ifndef STANDALONE +#ifdef BUILD_PRICES +#include "games/prices.cpp" +#else +#include "games/tetris.cpp" +#endif +void GAMEJSON(UniValue &obj,struct games_player *P); /* ./c cclib rng 17 \"[%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,250]\" @@ -51,24 +205,6 @@ ./c cclib events 17 \"[%226d%22,%229433dc3749aece1bd568f374a45da3b0bc6856990d7da3cd175399577940a775%22,1]\" */ -int32_t games_payloadrecv(CPubKey pk,uint32_t timestamp,std::vector payload) -{ - uint256 gametxid; int32_t i,len; char str[67]; uint32_t eventid = 0; - if ( (len= payload.size()) > 36 ) - { - len -= 36; - for (i=0; i<32; i++) - ((uint8_t *)&gametxid)[i] = payload[len+i]; - eventid = (uint32_t)payload[len+32]; - eventid |= (uint32_t)payload[len+33] << 8; - eventid |= (uint32_t)payload[len+34] << 16; - eventid |= (uint32_t)payload[len+35] << 24; - for (i=0; i> 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; @@ -355,7 +477,9 @@ int32_t games_event(uint32_t timestamp,uint256 gametxid,int32_t eventid,std::vec games_payloadrecv(mypk,timestamp,payload); komodo_sendmessage(4,8,"events",vopret); return(0); - } else return(-1); + } + fprintf(stderr,"games_eventsign error\n"); + return(-1); } UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) @@ -431,14 +555,14 @@ void komodo_netevent(std::vector message) { if ( (rand() % 10) == 0 ) { - fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); + //fprintf(stderr,"relay message.[%d]\n",(int32_t)message.size()); komodo_sendmessage(2,2,"events",message); } } } //for (i=0; i playerdata) -{ - struct games_player P; int32_t i; char packitemstr[512]; - if ( playerdata.size() > 0 ) - { - for (i=0; i>16,P.level,P.experience,P.dungeonlevel); - for (i=0; i playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname,uint256 gametxid) { int32_t i,vout,spentvini,numvouts,n=0; uint256 txid,spenttxid,hashBlock; struct games_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx; @@ -596,7 +700,6 @@ UniValue games_playerobj(std::vector playerdata,uint256 playertxid,uint } datastr[i<<1] = 0; } - int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,pad; for (i=0; i playerdata,uint256 playertxid,uint free(datastr); } obj.push_back(Pair("pack",a)); - obj.push_back(Pair("packsize",(int64_t)P.packsize)); - obj.push_back(Pair("hitpoints",(int64_t)P.hitpoints)); - obj.push_back(Pair("strength",(int64_t)(P.strength&0xffff))); - obj.push_back(Pair("maxstrength",(int64_t)(P.strength>>16))); - obj.push_back(Pair("level",(int64_t)P.level)); - obj.push_back(Pair("experience",(int64_t)P.experience)); - obj.push_back(Pair("dungeonlevel",(int64_t)P.dungeonlevel)); + GAMEPLAYERJSON(obj,&P); obj.push_back(Pair("chain",symbol)); obj.push_back(Pair("pname",pname)); return(obj); @@ -735,6 +832,24 @@ int32_t games_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx, return(0); } +int64_t games_buyins(uint256 gametxid,int32_t maxplayers) +{ + int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; int64_t buyins = 0; + for (i=0; i= 0 ) + { + if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) + { + if ( spenttx.vout[0].nValue > GAMES_REGISTRATIONSIZE ) + buyins += (spenttx.vout[0].nValue - GAMES_REGISTRATIONSIZE); + } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); + } //else fprintf(stderr,"vout %d is unspent\n",vout); + } + return(buyins); +} + uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mygamesaddr) { CBlockIndex *pindex; int32_t ht,openslots,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx; @@ -762,6 +877,7 @@ uint64_t games_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 obj.push_back(Pair("alive",games_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); obj.push_back(Pair("openslots",openslots)); obj.push_back(Pair("numplayers",numplayers)); + obj.push_back(Pair("buyins",ValueFromAmount(games_buyins(gametxid,maxplayers)))); } obj.push_back(Pair("maxplayers",maxplayers)); obj.push_back(Pair("buyin",ValueFromAmount(buyin))); @@ -786,6 +902,27 @@ UniValue games_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *param } else return(cclib_error(result,"couldnt reparse params")); } +void disp_gamesplayerdata(std::vector playerdata) +{ + struct games_player P; int32_t i; char packitemstr[512],str[512]; + if ( playerdata.size() > 0 ) + { + for (i=0; i &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) +int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,gamesevent **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) { - int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64],*keystrokes=0; + int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64]; gamesevent *keystrokes=0; batonvalue = numkeys = numplayers = batonht = 0; playertxid = batontxid = zeroid; if ( keystrokesp != 0 ) *keystrokesp = 0; for (i=0; i= 0 ) { if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) @@ -856,7 +993,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke if ( matches == 1 ) { numvouts = matchtx.vout.size(); - //fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); +//fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); if ( games_registeropretdecode(txid,tokenid,playertxid,matchtx.vout[numvouts-1].scriptPubKey) == 'R' )//&& txid == gametxid ) { //fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); @@ -886,6 +1023,7 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); if ( spentvini != 0 ) // game is over? { + //fprintf(stderr,"gameisover n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); return(0); } if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) @@ -893,10 +1031,17 @@ int32_t games_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **ke uint256 g,b; CPubKey p; std::vector k; if ( games_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) { - keystrokes = (char *)realloc(keystrokes,numkeys + (int32_t)k.size()); - for (i=0; i &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) +gamesevent *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *gamesaddr) { - CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; + CPubKey gamespk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64]; gamesevent *keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct games_player P,endP; gamespk = GetUnspendable(cp,0); *numkeysp = 0; seed = 0; @@ -1215,6 +1360,7 @@ char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto if ( (retval= games_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,gamesaddr,numplayers,symbol,pname)) == 0 ) { UniValue obj; + //fprintf(stderr,"got baton\n"); seed = games_gamefields(obj,maxplayers,buyin,gametxid,gamesaddr); //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Games_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); memset(&P,0,sizeof(P)); @@ -1230,7 +1376,7 @@ char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto sprintf(fname,"%s.%llu.0",GAMENAME,(long long)seed); if ( (fp= fopen(fname,"wb")) != 0 ) { - if ( fwrite(keystrokes,1,numkeys,fp) != numkeys ) + if ( fwrite(keystrokes,sizeof(*keystrokes),numkeys,fp) != numkeys ) fprintf(stderr,"error writing %s\n",fname); fclose(fp); } @@ -1242,7 +1388,6 @@ char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto fclose(fp); } } - //fprintf(stderr,"call replay2\n"); num = games_replay2(newplayer,seed,keystrokes,numkeys,playerdata.size()==0?0:&P,0); newdata.resize(num); for (i=0; i no playerdata\n"); + sprintf(str,"zero value character -> no playerdata\n"); newdata.resize(0); *numkeysp = numkeys; return(keystrokes); - /* P.gold = (P.gold * 8) / 10; - if ( keystrokes != 0 ) - { - free(keystrokes); - keystrokes = 0; - *numkeysp = 0; - return(keystrokes); - }*/ } else { - sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); - //fprintf(stderr,"%s\n",str); *numkeysp = numkeys; return(keystrokes); } @@ -1288,7 +1423,7 @@ char *games_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vecto UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - UniValue result(UniValue::VOBJ); CPubKey pk,gamespk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],gamesaddr[64],*pubstr,*hexstr,*keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; + UniValue result(UniValue::VOBJ); CPubKey pk,gamespk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],gamesaddr[64],*pubstr,*hexstr; gamesevent *keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; pk = pubkey2pk(Mypubkey()); gamespk = GetUnspendable(cp,0); result.push_back(Pair("name","games")); @@ -1322,10 +1457,25 @@ UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { result.push_back(Pair("status","success")); flag = 1; - hexstr = (char *)malloc(numkeys*2 + 1); + hexstr = (char *)calloc(1,sizeof(gamesevent)*numkeys*2 + 1); for (i=0; iamulet != 0 ) - mult *= 5; - dungeonlevel = P->dungeonlevel; - if ( P->amulet != 0 && dungeonlevel < 26 ) - dungeonlevel = 26; - cashout = (uint64_t)P->gold * P->gold * mult * dungeonlevel; - return(cashout); -} - -int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) -{ - static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,gamesaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; - *cashoutp = 0; - gamespk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,gamesaddr,gamespk,pk); - if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) - { - free(keystrokes); - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - - for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); - } - *cashoutp = 0; - return(0); - } - } - if ( gametxid != prevgame ) - { - prevgame = gametxid; - bad++; - disp_gamesplayerdata(newdata); - disp_gamesplayerdata(playerdata); - fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,gamesaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); - } - } - sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); - remove(fname); - //fprintf(stderr,"no keys games_extractgame %s\n",gametxid.GetHex().c_str()); - return(-1); -} - -UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,char *method) { //vin0 -> highlander vout from creategame TCBOO //vin1 -> keystrokes baton of completed game, must be last to quit or first to win, only spent registration batons matter. If more than 60 blocks since last keystrokes, it is forfeit @@ -1449,8 +1506,8 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) // vout0 -> playerdata marker // vout0 -> 1% ingame gold // get any playerdata, get all keystrokes, replay game and compare final state - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); char *method = (char *)"bailout"; - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed; int64_t buyin,batonvalue,inputsum,cashout=0,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,numkeys,maxplayers,batonht,batonvout; char mygamesaddr[64],str[512]; gamesevent *keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,gamespk; uint8_t player[10000],mypriv[32],funcid; struct CCcontract_info *cpTokens, tokensC; if ( txfee == 0 ) @@ -1462,15 +1519,8 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) result.push_back(Pair("method",method)); result.push_back(Pair("mygamesaddr",mygamesaddr)); if ( strcmp(method,"bailout") == 0 ) - { funcid = 'Q'; - //mult = 10; //100000; - } - else - { - funcid = 'H'; - //mult = 20; //200000; - } + else funcid = 'H'; if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) { if ( n > 0 ) @@ -1508,11 +1558,10 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) newdata[i] = player[i]; ((uint8_t *)&P)[i] = player[i]; } - if ( (P.gold <= 0 || P.hitpoints <= 0 || (P.strength&0xffff) <= 0 || P.level <= 0 || P.experience <= 0 || P.dungeonlevel <= 0) ) + if ( disp_gamesplayer(str,&P) < 0 ) { //fprintf(stderr,"zero value character was killed -> no playerdata\n"); newdata.resize(0); - //P.gold = (P.gold * 8) / 10; } else { @@ -1520,17 +1569,17 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); cashout = games_cashout(&P); - fprintf(stderr,"\nextracted $$$gold.%d -> %.8f GAME hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); + fprintf(stderr,"\ncashout %.8f extracted %s\n",(double)cashout/COIN,str); if ( funcid == 'H' && maxplayers > 1 ) { - if ( P.amulet == 0 ) + /*if ( P.amulet == 0 ) { if ( numplayers != maxplayers ) return(cclib_error(result,"numplayers != maxplayers")); else if ( games_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) return(cclib_error(result,"highlander must be a winner or last one standing")); - } - cashout += numplayers * buyin; + }*/ + cashout += games_buyins(gametxid,maxplayers);//numplayers * buyin; } if ( cashout > 0 ) { @@ -1572,6 +1621,16 @@ UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } +UniValue games_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + return(games_finish(txfee,cp,params,(char *)"bailout")); +} + +UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) +{ + return(games_finish(txfee,cp,params,(char *)"highlander")); +} + UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { UniValue result(UniValue::VOBJ),a(UniValue::VARR); int64_t buyin; uint256 tokenid,gametxid,txid,hashBlock; CTransaction playertx,tx; int32_t maxplayers,vout,numvouts; std::vector playerdata; CPubKey gamespk,mypk,pk; std::string symbol,pname; char coinaddr[64]; @@ -1657,1928 +1716,96 @@ UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } -bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) +UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - return(true); -} - -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis) -{ - return(-1); -} - -void games_packitemstr(char *packitemstr,struct games_packitem *item) -{ - sprintf(packitemstr,"not yet"); -} -#else - - -#include -#include -#include -#include -#include -#include -#include - -char USERPASS[8192]; uint16_t GAMES_PORT; -char Gametxidstr[67]; -char *clonestr(char *str); - -#define MAXSTR 1024 -char whoami[MAXSTR]; - -#define SMALLVAL 0.000000000000001 -#define SATOSHIDEN ((uint64_t)100000000L) -#define dstr(x) ((double)(x) / SATOSHIDEN) -#define KOMODO_ASSETCHAIN_MAXLEN 65 -char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],IPADDRESS[100]; - -#ifndef _BITS256 -#define _BITS256 -union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; -typedef union _bits256 bits256; -#endif - -#ifdef _WIN32 -#ifdef _MSC_VER -int gettimeofday(struct timeval * tp, struct timezone * tzp) -{ - // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's - static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL); - - SYSTEMTIME system_time; - FILETIME file_time; - uint64_t time; - - GetSystemTime(&system_time); - SystemTimeToFileTime(&system_time, &file_time); - time = ((uint64_t)file_time.dwLowDateTime); - time += ((uint64_t)file_time.dwHighDateTime) << 32; - - tp->tv_sec = (long)((time - EPOCH) / 10000000L); - tp->tv_usec = (long)(system_time.wMilliseconds * 1000); - return 0; -} -#endif // _MSC_VER -#endif - - - -double OS_milliseconds() -{ - struct timeval tv; double millis; -#ifdef __MINGW32__ - mingw_gettimeofday(&tv,NULL); -#else - gettimeofday(&tv,NULL); -#endif - millis = ((double)tv.tv_sec * 1000. + (double)tv.tv_usec / 1000.); - //printf("tv_sec.%ld usec.%d %f\n",tv.tv_sec,tv.tv_usec,millis); - return(millis); -} - -int32_t _unhex(char c) -{ - if ( c >= '0' && c <= '9' ) - return(c - '0'); - else if ( c >= 'a' && c <= 'f' ) - return(c - 'a' + 10); - else if ( c >= 'A' && c <= 'F' ) - return(c - 'A' + 10); - return(-1); -} - -int32_t is_hexstr(char *str,int32_t n) -{ - int32_t i; - if ( str == 0 || str[0] == 0 ) - return(0); - for (i=0; str[i]!=0; i++) + CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); + UniValue result(UniValue::VOBJ); std::string rawtx; int64_t amount,inputsum; CPubKey gamespk,mypk; CScript opret; + if ( params != 0 && cJSON_GetArraySize(params) == 1 ) { - if ( n > 0 && i >= n ) - break; - if ( _unhex(str[i]) < 0 ) - break; - } - if ( n == 0 ) - return(i); - return(i == n); -} - -int32_t unhex(char c) -{ - int32_t hex; - if ( (hex= _unhex(c)) < 0 ) - { - //printf("unhex: illegal hexchar.(%c)\n",c); - } - return(hex); -} - -unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); } - -int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex) -{ - int32_t adjust,i = 0; - //printf("decode.(%s)\n",hex); - if ( is_hexstr(hex,n) <= 0 ) - { - memset(bytes,0,n); - return(n); - } - if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) - hex[--n] = 0; - if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) ) - { - if ( n > 0 ) + amount = jdouble(jitem(params,0),0) * COIN + 0.0000000049; + gamespk = GetUnspendable(cp,0); + mypk = pubkey2pk(Mypubkey()); + if ( amount > GAMES_TXFEE ) { - bytes[0] = unhex(hex[0]); - printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex)); - } - bytes++; - hex++; - adjust = 1; - } else adjust = 0; - if ( n > 0 ) - { - for (i=0; i>4) & 0xf); - hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf); - //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]); - } - hexbytes[len*2] = 0; - //printf("len.%ld\n",len*2+1); - return((int32_t)len*2+1); -} - -char *bits256_str(char hexstr[65],bits256 x) -{ - init_hexbytes_noT(hexstr,x.bytes,sizeof(x)); - return(hexstr); -} - -long _stripwhite(char *buf,int accept) -{ - int32_t i,j,c; - if ( buf == 0 || buf[0] == 0 ) - return(0); - for (i=j=0; buf[i]!=0; i++) - { - buf[j] = c = buf[i]; - if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') ) - j++; - } - buf[j] = 0; - return(j); -} - -char *parse_conf_line(char *line,char *field) -{ - line += strlen(field); - for (; *line!='='&&*line!=0; line++) - break; - if ( *line == 0 ) - return(0); - if ( *line == '=' ) - line++; - while ( line[strlen(line)-1] == '\r' || line[strlen(line)-1] == '\n' || line[strlen(line)-1] == ' ' ) - line[strlen(line)-1] = 0; - //printf("LINE.(%s)\n",line); - _stripwhite(line,0); - return(clonestr(line)); -} - -int32_t safecopy(char *dest,char *src,long len) -{ - int32_t i = -1; - if ( src != 0 && dest != 0 && src != dest ) - { - if ( dest != 0 ) - memset(dest,0,len); - for (i=0; i buflen ) - { - *allocsizep = filesize; - *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); - } - rewind(fp); - if ( buf == 0 ) - printf("Null buf ???\n"); - else - { - if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) - printf("error reading filesize.%ld\n",(long)filesize); - buf[filesize] = 0; - } - fclose(fp); - *lenp = filesize; - //printf("loaded.(%s)\n",buf); - } //else printf("OS_loadfile couldnt load.(%s)\n",fname); - return(buf); -} - -uint8_t *OS_fileptr(long *allocsizep,char *fname) -{ - long filesize = 0; uint8_t *buf = 0; void *retptr; - *allocsizep = 0; - retptr = OS_loadfile(fname,&buf,&filesize,allocsizep); - return((uint8_t *)retptr); -} - -struct MemoryStruct { char *memory; size_t size; }; -struct return_string { char *ptr; size_t len; }; - -// return data from the server -#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) -#define CURL_GLOBAL_SSL (1<<0) -#define CURL_GLOBAL_WIN32 (1<<1) - - -/************************************************************************ - * - * Initialize the string handler so that it is thread safe - * - ************************************************************************/ - -void init_string(struct return_string *s) -{ - s->len = 0; - s->ptr = (char *)calloc(1,s->len+1); - if ( s->ptr == NULL ) - { - fprintf(stderr,"init_string malloc() failed\n"); - exit(-1); - } - s->ptr[0] = '\0'; -} - -/************************************************************************ - * - * Use the "writer" to accumulate text until done - * - ************************************************************************/ - -size_t accumulatebytes(void *ptr,size_t size,size_t nmemb,struct return_string *s) -{ - size_t new_len = s->len + size*nmemb; - s->ptr = (char *)realloc(s->ptr,new_len+1); - if ( s->ptr == NULL ) - { - fprintf(stderr, "accumulate realloc() failed\n"); - exit(-1); - } - memcpy(s->ptr+s->len,ptr,size*nmemb); - s->ptr[new_len] = '\0'; - s->len = new_len; - return(size * nmemb); -} - -/************************************************************************ - * - * return the current system time in milliseconds - * - ************************************************************************/ - -#define EXTRACT_BITCOIND_RESULT // if defined, ensures error is null and returns the "result" field -#ifdef EXTRACT_BITCOIND_RESULT - -/************************************************************************ - * - * perform post processing of the results - * - ************************************************************************/ - -char *post_process_bitcoind_RPC(char *debugstr,char *command,char *rpcstr,char *params) -{ - long i,j,len; char *retstr = 0; cJSON *json,*result,*error; - //printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); - if ( command == 0 || rpcstr == 0 || rpcstr[0] == 0 ) - { - if ( strcmp(command,"signrawtransaction") != 0 ) - printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s.[%s]\n",debugstr,command,rpcstr); - return(rpcstr); - } - json = cJSON_Parse(rpcstr); - if ( json == 0 ) - { - printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC.%s can't parse.(%s) params.(%s)\n",debugstr,command,rpcstr,params); - free(rpcstr); - return(0); - } - result = cJSON_GetObjectItem(json,"result"); - error = cJSON_GetObjectItem(json,"error"); - if ( error != 0 && result != 0 ) - { - if ( (error->type&0xff) == cJSON_NULL && (result->type&0xff) != cJSON_NULL ) - { - retstr = cJSON_Print(result); - len = strlen(retstr); - if ( retstr[0] == '"' && retstr[len-1] == '"' ) + if ( (inputsum= AddNormalinputs(mtx,mypk,amount+GAMES_TXFEE,64)) >= amount+GAMES_TXFEE ) { - for (i=1,j=0; itype&0xff) != cJSON_NULL || (result->type&0xff) != cJSON_NULL ) - { - if ( strcmp(command,"signrawtransaction") != 0 ) - printf("<<<<<<<<<<< bitcoind_RPC: %s post_process_bitcoind_RPC (%s) error.%s\n",debugstr,command,rpcstr); - } - free(rpcstr); - } else retstr = rpcstr; - free_json(json); - //fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC: postprocess returns.(%s)\n",retstr); - return(retstr); -} -#endif - -#ifdef _WIN32 -#ifdef _MSC_VER -#define sleep(x) Sleep(1000*(x)) -#endif -#endif - -/************************************************************************ - * - * perform the query - * - ************************************************************************/ - -char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params) -{ - static int didinit,count,count2; static double elapsedsum,elapsedsum2; - struct curl_slist *headers = NULL; struct return_string s; CURLcode res; CURL *curl_handle; - char *bracket0,*bracket1,*databuf = 0; long len; int32_t specialcase,numretries; double starttime; - if ( didinit == 0 ) - { - didinit = 1; - curl_global_init(CURL_GLOBAL_ALL); //init the curl session - } - numretries = 0; - if ( debugstr != 0 && strcmp(debugstr,"BTCD") == 0 && command != 0 && strcmp(command,"SuperNET") == 0 ) - specialcase = 1; - else specialcase = 0; - if ( url[0] == 0 ) - strcpy(url,"http://127.0.0.1:7876/nxt"); - if ( specialcase != 0 && 0 ) - printf("<<<<<<<<<<< bitcoind_RPC: debug.(%s) url.(%s) command.(%s) params.(%s)\n",debugstr,url,command,params); -try_again: - if ( retstrp != 0 ) - *retstrp = 0; - starttime = OS_milliseconds(); - curl_handle = curl_easy_init(); - init_string(&s); - headers = curl_slist_append(0,"Expect:"); - - curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); - curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); - curl_easy_setopt(curl_handle,CURLOPT_URL, url); - curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function - curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback - curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash - curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback - if ( strncmp(url,"https",5) == 0 ) - { - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); - curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYHOST,0); - } - if ( userpass != 0 ) - curl_easy_setopt(curl_handle,CURLOPT_USERPWD, userpass); - databuf = 0; - if ( params != 0 ) - { - if ( command != 0 && specialcase == 0 ) - { - len = strlen(params); - if ( len > 0 && params[0] == '[' && params[len-1] == ']' ) { - bracket0 = bracket1 = (char *)""; + mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount,gamespk)); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,GAMES_TXFEE,opret); + return(games_rawtxresult(result,rawtx,1)); } else { - bracket0 = (char *)"["; - bracket1 = (char *)"]"; + result.push_back(Pair("result","error")); + result.push_back(Pair("error","not enough funds")); } - - databuf = (char *)malloc(256 + strlen(command) + strlen(params)); - sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); - //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); - // - } //else if ( specialcase != 0 ) fprintf(stderr,"databuf.(%s)\n",params); - curl_easy_setopt(curl_handle,CURLOPT_POST,1L); - if ( databuf != 0 ) - curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,databuf); - else curl_easy_setopt(curl_handle,CURLOPT_POSTFIELDS,params); - } - //laststart = milliseconds(); - res = curl_easy_perform(curl_handle); - curl_slist_free_all(headers); - curl_easy_cleanup(curl_handle); - if ( databuf != 0 ) // clean up temporary buffer - { - free(databuf); - databuf = 0; - } - if ( res != CURLE_OK ) - { - numretries++; - if ( specialcase != 0 ) - { - printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); - free(s.ptr); - return(0); - } - else if ( numretries >= 1 ) - { - //printf("Maximum number of retries exceeded!\n"); - free(s.ptr); - return(0); - } - if ( (rand() % 1000) == 0 ) - printf( "curl_easy_perform() failed: %s %s.(%s %s), retries: %d\n",curl_easy_strerror(res),debugstr,url,command,numretries); - free(s.ptr); - sleep((1< (%s)\n",params,s.ptr); - count2++; - elapsedsum2 += (OS_milliseconds() - starttime); - if ( (count2 % 10000) == 0) - printf("%d: ave %9.6f | elapsed %.3f millis | NXT calls.(%s) cmd.(%s)\n",count2,elapsedsum2/count2,(double)(OS_milliseconds() - starttime),url,command); - return(s.ptr); + result.push_back(Pair("result","error")); + result.push_back(Pair("error","amount too small")); } } - printf("bitcoind_RPC: impossible case\n"); - free(s.ptr); - return(0); -} - -static size_t WriteMemoryCallback(void *ptr,size_t size,size_t nmemb,void *data) -{ - size_t realsize = (size * nmemb); - struct MemoryStruct *mem = (struct MemoryStruct *)data; - mem->memory = (char *)((ptr != 0) ? realloc(mem->memory,mem->size + realsize + 1) : malloc(mem->size + realsize + 1)); - if ( mem->memory != 0 ) - { - if ( ptr != 0 ) - memcpy(&(mem->memory[mem->size]),ptr,realsize); - mem->size += realsize; - mem->memory[mem->size] = 0; - } - //printf("got %d bytes\n",(int32_t)(size*nmemb)); - return(realsize); -} - -char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char *hdr0,char *hdr1,char *hdr2,char *hdr3) -{ - struct MemoryStruct chunk; CURL *cHandle; long code; struct curl_slist *headers = 0; - if ( (cHandle= *cHandlep) == NULL ) - *cHandlep = cHandle = curl_easy_init(); - else curl_easy_reset(cHandle); - //#ifdef DEBUG - //curl_easy_setopt(cHandle,CURLOPT_VERBOSE, 1); - //#endif - curl_easy_setopt(cHandle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); - curl_easy_setopt(cHandle,CURLOPT_SSL_VERIFYPEER,0); - //curl_easy_setopt(cHandle,CURLOPT_SSLVERSION,1); - curl_easy_setopt(cHandle,CURLOPT_URL,url); - curl_easy_setopt(cHandle,CURLOPT_CONNECTTIMEOUT,10); - if ( userpass != 0 && userpass[0] != 0 ) - curl_easy_setopt(cHandle,CURLOPT_USERPWD,userpass); - if ( postfields != 0 && postfields[0] != 0 ) - { - curl_easy_setopt(cHandle,CURLOPT_POST,1); - curl_easy_setopt(cHandle,CURLOPT_POSTFIELDS,postfields); - } - if ( hdr0 != NULL && hdr0[0] != 0 ) - { - //printf("HDR0.(%s) HDR1.(%s) HDR2.(%s) HDR3.(%s)\n",hdr0!=0?hdr0:"",hdr1!=0?hdr1:"",hdr2!=0?hdr2:"",hdr3!=0?hdr3:""); - headers = curl_slist_append(headers,hdr0); - if ( hdr1 != 0 && hdr1[0] != 0 ) - headers = curl_slist_append(headers,hdr1); - if ( hdr2 != 0 && hdr2[0] != 0 ) - headers = curl_slist_append(headers,hdr2); - if ( hdr3 != 0 && hdr3[0] != 0 ) - headers = curl_slist_append(headers,hdr3); - } //headers = curl_slist_append(0,"Expect:"); - if ( headers != 0 ) - curl_easy_setopt(cHandle,CURLOPT_HTTPHEADER,headers); - //res = curl_easy_perform(cHandle); - memset(&chunk,0,sizeof(chunk)); - curl_easy_setopt(cHandle,CURLOPT_WRITEFUNCTION,WriteMemoryCallback); - curl_easy_setopt(cHandle,CURLOPT_WRITEDATA,(void *)&chunk); - curl_easy_perform(cHandle); - curl_easy_getinfo(cHandle,CURLINFO_RESPONSE_CODE,&code); - if ( headers != 0 ) - curl_slist_free_all(headers); - if ( code != 200 ) - printf("(%s) server responded with code %ld (%s)\n",url,code,chunk.memory); - return(chunk.memory); -} - -uint16_t _komodo_userpass(char *username, char *password, FILE *fp) -{ - char *rpcuser,*rpcpassword,*str,*ipaddress,line[8192]; uint16_t port = 0; - rpcuser = rpcpassword = 0; - username[0] = password[0] = 0; - while ( fgets(line,sizeof(line),fp) != 0 ) - { - if ( line[0] == '#' ) - continue; - //printf("line.(%s) %p %p\n",line,strstr(line,(char *)"rpcuser"),strstr(line,(char *)"rpcpassword")); - if ( (str= strstr(line,(char *)"rpcuser")) != 0 ) - rpcuser = parse_conf_line(str,(char *)"rpcuser"); - else if ( (str= strstr(line,(char *)"rpcpassword")) != 0 ) - rpcpassword = parse_conf_line(str,(char *)"rpcpassword"); - else if ( (str= strstr(line,(char *)"rpcport")) != 0 ) - { - port = atoi(parse_conf_line(str,(char *)"rpcport")); - //fprintf(stderr,"rpcport.%u in file\n",port); - } - else if ( (str= strstr(line,(char *)"ipaddress")) != 0 ) - { - ipaddress = parse_conf_line(str,(char *)"ipaddress"); - strcpy(IPADDRESS,ipaddress); - } - } - if ( rpcuser != 0 && rpcpassword != 0 ) - { - strcpy(username,rpcuser); - strcpy(password,rpcpassword); - } - //printf("rpcuser.(%s) rpcpassword.(%s) %u ipaddress.%s\n",rpcuser,rpcpassword,port,ipaddress); - if ( rpcuser != 0 ) - free(rpcuser); - if ( rpcpassword != 0 ) - free(rpcpassword); - return(port); -} - -uint16_t komodo_userpass(char *userpass,char *symbol) -{ - FILE *fp; uint16_t port = 0; char fname[512],username[512],password[512],confname[KOMODO_ASSETCHAIN_MAXLEN]; - userpass[0] = 0; - if ( strcmp("KMD",symbol) == 0 ) - { -#ifdef __APPLE__ - sprintf(confname,"Komodo.conf"); -#else - sprintf(confname,"komodo.conf"); -#endif - } - else sprintf(confname,"%s.conf",symbol); - //komodo_statefname(fname,symbol,confname); - if ( (fp= fopen(confname,"rb")) != 0 ) - { - port = _komodo_userpass(username,password,fp); - sprintf(userpass,"%s:%s",username,password); - if ( strcmp(symbol,ASSETCHAINS_SYMBOL) == 0 ) - strcpy(USERPASS,userpass); - fclose(fp); - } - return(port); -} - -#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True) - -char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) -{ - //static void *cHandle; - char url[512],*retstr=0,*retstr2=0,postdata[8192]; - if ( params == 0 || params[0] == 0 ) - params = (char *)"[]"; - if ( strlen(params) < sizeof(postdata)-128 ) - { - sprintf(url,(char *)"http://%s:%u",IPADDRESS,port); - sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); - //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,USERPASS); - retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); - //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); - } - return(retstr2); -} - -int32_t issue_games_events(bits256 gametxid,uint32_t eventid,int32_t c) -{ - static FILE *fp; - char params[512],*retstr,str[65]; cJSON *retjson,*resobj; int32_t retval = -1; - if ( fp == 0 ) - fp = fopen("events.log","wb"); - sprintf(params,"[\"events\",\"17\",\"[%%22%08x%%22,%%22%s%%22,%u]\"]",c,bits256_str(str,gametxid),eventid); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - retval = 0; - if ( fp != 0 ) - { - fprintf(fp,"%s\n",jprint(resobj,0)); - fflush(fp); - } - } - free_json(retjson); - } else fprintf(fp,"error parsing %s\n",retstr); - free(retstr); - } else fprintf(fp,"error issuing method %s\n",params); - return(retval); -} - -int32_t games_sendrawtransaction(char *rawtx) -{ - char *params,*retstr,*hexstr; cJSON *retjson,*resobj; int32_t retval = -1; - params = (char *)malloc(strlen(rawtx) + 16); - sprintf(params,"[\"%s\"]",rawtx); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"sendrawtransaction",params,GAMES_PORT)) != 0 ) - { - if ( 0 ) // causes 4th level crash - { - static FILE *fp; - if ( fp == 0 ) - fp = fopen("games.sendlog","wb"); - if ( fp != 0 ) - { - fprintf(fp,"%s\n",retstr); - fflush(fp); - } - } - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 ) - { - if ( (hexstr= jstr(resobj,0)) != 0 && is_hexstr(hexstr,64) == 64 ) - retval = 0; - } - free_json(retjson); - } - - /* log sendrawtx result in file */ - - /* - FILE *debug_file; - debug_file = fopen("tx_debug.log", "a"); - fprintf(debug_file, "%s\n", retstr); - fflush(debug_file); - fclose(debug_file); - */ - - free(retstr); - } - free(params); - return(retval); -} - -int32_t games_progress(struct games_state *rs,int32_t waitflag,uint64_t seed,char *keystrokes,int32_t num) -{ - char cmd[16384],hexstr[16384],params[32768],*retstr,*errstr,*rawtx,*pastkeys,*keys; int32_t i,len,numpastkeys,retflag = -1; cJSON *retjson,*resobj; uint8_t *pastcmp; - if ( rs->guiflag != 0 && Gametxidstr[0] != 0 ) - { - if ( rs->keystrokeshex != 0 ) - { - if ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) - { - if ( waitflag == 0 ) - return(0); - else if ( 0 ) - { - while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) - { - //fprintf(stderr,"pre-rebroadcast\n"); - sleep(10); - } - } - } - free(rs->keystrokeshex), rs->keystrokeshex = 0; - } - if ( 0 && (pastkeys= games_keystrokesload(&numpastkeys,seed,1)) != 0 ) - { - sprintf(params,"[\"extract\",\"17\",\"[%%22%s%%22]\"]",Gametxidstr); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (keys= jstr(resobj,(char *)"keystrokes")) != 0 ) - { - len = strlen(keys) / 2; - pastcmp = (uint8_t *)malloc(len + 1); - decode_hex(pastcmp,len,keys); - fprintf(stderr,"keystrokes.(%s) vs pastkeys\n",keys); - for (i=0; i> keystrokes.log",ASSETCHAINS_SYMBOL,Gametxidstr,hexstr); - if ( system(cmd) != 0 ) - fprintf(stderr,"error issuing (%s)\n",cmd); - } - else - { - static FILE *fp; - if ( fp == 0 ) - fp = fopen("keystrokes.log","a"); - sprintf(params,"[\"keystrokes\",\"17\",\"[%%22%s%%22,%%22%s%%22]\"]",Gametxidstr,hexstr); - if ( (retstr= komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT)) != 0 ) - { - if ( fp != 0 ) - { - fprintf(fp,"%s\n",params); - fprintf(fp,"%s\n",retstr); - fflush(fp); - } - if ( (retjson= cJSON_Parse(retstr)) != 0 ) - { - if ( (resobj= jobj(retjson,(char *)"result")) != 0 && (rawtx= jstr(resobj,(char *)"hex")) != 0 ) - { - if ( rs->keystrokeshex != 0 ) - free(rs->keystrokeshex); - if ( (errstr= jstr(resobj,(char *)"error")) == 0 ) - { - rs->keystrokeshex = (char *)malloc(strlen(rawtx)+1); - strcpy(rs->keystrokeshex,rawtx); - retflag = 1; - } else fprintf(stderr,"error sending keystrokes tx\n"), sleep(1); - //fprintf(stderr,"set keystrokestx <- %s\n",rs->keystrokeshex); - } - free_json(retjson); - } - free(retstr); - } - if ( 0 && waitflag != 0 && rs->keystrokeshex != 0 ) - { - while ( games_sendrawtransaction(rs->keystrokeshex) == 0 ) - { - //fprintf(stderr,"post-rebroadcast\n"); - sleep(3); - } - free(rs->keystrokeshex), rs->keystrokeshex = 0; - } - } - } - return(retflag); -} - -int32_t games_setplayerdata(struct games_state *rs,char *gametxidstr) -{ - char cmd[32768]; int32_t i,n,retval=-1; char params[1024],*filestr=0,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item,*resultjson; - if ( rs->guiflag == 0 ) - return(-1); - if ( gametxidstr == 0 || *gametxidstr == 0 ) - return(retval); - if ( 0 ) - { - sprintf(fname,"%s.gameinfo",gametxidstr); - sprintf(cmd,"./komodo-cli -ac_name=%s cclib gameinfo 17 \\\"[%%22%s%%22]\\\" > %s",ASSETCHAINS_SYMBOL,gametxidstr,fname); - if ( system(cmd) != 0 ) - fprintf(stderr,"error issuing (%s)\n",cmd); - else filestr = (char *)OS_fileptr(&allocsize,fname); - } else { - sprintf(params,"[\"gameinfo\",\"17\",\"[%%22%s%%22]\"]",gametxidstr); - filestr = komodo_issuemethod(USERPASS,(char *)"cclib",params,GAMES_PORT); + result.push_back(Pair("result","error")); + result.push_back(Pair("error","couldnt parse")); } - if ( filestr != 0 ) + return(result); +} + +int32_t games_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) +{ + static uint32_t good,bad; static uint256 prevgame; + char str[512],gamesaddr[64],str2[67],fname[64]; gamesevent *keystrokes; int32_t i,numkeys; std::vector newdata; uint64_t seed; CPubKey gamespk; struct games_player P; + *cashoutp = 0; + gamespk = GetUnspendable(cp,0); + GetCCaddress1of2(cp,gamesaddr,gamespk,pk); + if ( (keystrokes= games_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,gamesaddr)) != 0 ) { - if ( (retjson= cJSON_Parse(filestr)) != 0 && (resultjson= jobj(retjson,(char *)"result")) != 0 ) + free(keystrokes); + sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); + remove(fname); + for (i=0; iP,(int32_t)strlen(datastr)/2,datastr); - fprintf(stderr,"set pname[%s] %s\n",pname==0?"":pname,jprint(item,0)); - rs->restoring = 1; - } - } - } + prevgame = gametxid; + good++; } - } - free_json(retjson); - } - free(filestr); - } - return(retval); -} - -#ifdef _WIN32 -#ifdef _MSC_VER -__inline int msver(void) { - switch (_MSC_VER) { - case 1500: return 2008; - case 1600: return 2010; - case 1700: return 2012; - case 1800: return 2013; - case 1900: return 2015; - //case 1910: return 2017; - default: return (_MSC_VER / 100); - } -} - -static inline bool is_x64(void) { -#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) - return 1; -#elif defined(__amd64__) || defined(__amd64) || defined(_M_X64) || defined(_M_IA64) - return 1; -#else - return 0; -#endif -} - -#define BUILD_DATE __DATE__ " " __TIME__ -#endif // _WIN32 -#endif // _MSC_VER - -int main(int argc, char **argv) -{ - uint64_t seed; FILE *fp = 0; int32_t i,j,c; char userpass[8192]; -#ifdef _WIN32 -#ifdef _MSC_VER - printf("*** games for Windows [ Build %s ] ***\n", BUILD_DATE); - const char* arch = is_x64() ? "64-bits" : "32-bits"; - printf(" Built with VC++ %d (%ld) %s\n\n", msver(), _MSC_FULL_VER, arch); -#endif -#endif - - for (i=j=0; argv[0][i]!=0&&j // for FILE -#include // for bool -#include -#include -#include -#include -#include -#include - -#ifdef BUILD_GAMESCC -#include "rogue/cursesd.h" -#else -#include -#endif - -/* - Convert a tetromino type to its corresponding cell. - */ -#define TYPE_TO_CELL(x) ((x)+1) - -/* - Strings for how you would print a tetris board. - */ -#define TC_EMPTY_STR " " -#define TC_BLOCK_STR "\u2588" - -/* - Questions about a tetris cell. - */ -#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) -#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) - -/* - How many cells in a tetromino? - */ -#define TETRIS 4 -/* - How many tetrominos? - */ -#define NUM_TETROMINOS 7 -/* - How many orientations of a tetromino? - */ -#define NUM_ORIENTATIONS 4 - -/* - Level constants. - */ -#define MAX_LEVEL 19 -#define LINES_PER_LEVEL 10 - -/* - A "cell" is a 1x1 block within a tetris board. - */ -typedef enum { - TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ -} tetris_cell; - -/* - A "type" is a type/shape of a tetromino. Not including orientation. - */ -typedef enum { - TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z -} tetris_type; - -/* - A row,column pair. Negative numbers allowed, because we need them for - offsets. - */ -typedef struct { - int row; - int col; -} tetris_location; - -/* - A "block" is a struct that contains information about a tetromino. - Specifically, what type it is, what orientation it has, and where it is. - */ -typedef struct { - int typ; - int ori; - tetris_location loc; -} tetris_block; - -/* - All possible moves to give as input to the game. - */ -typedef enum { - TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE -} tetris_move; - -/* - A game object! - */ -typedef struct { - /* - Game board stuff: - */ - int rows; - int cols; - char *board; - /* - Scoring information: - */ - int points; - int level; - /* - Falling block is the one currently going down. Next block is the one that - will be falling after this one. Stored is the block that you can swap out. - */ - tetris_block falling; - tetris_block next; - tetris_block stored; - /* - Number of game ticks until the block will move down. - */ - int ticks_till_gravity; - /* - Number of lines until you advance to the next level. - */ - int lines_remaining; -} tetris_game; - -/* - This array stores all necessary information about the cells that are filled by - each tetromino. The first index is the type of the tetromino (i.e. shape, - e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final - array contains 4 tetris_location objects, each mapping to an offset from a - point on the upper left that is the tetromino "origin". - */ -extern tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; - -/* - This array tells you how many ticks per gravity by level. Decreases as level - increases, to add difficulty. - */ -extern int GRAVITY_LEVEL[MAX_LEVEL+1]; - -// Data structure manipulation. -void tg_init(tetris_game *obj, int rows, int cols); -tetris_game *tg_create(int rows, int cols); -void tg_destroy(tetris_game *obj); -void tg_delete(tetris_game *obj); -tetris_game *tg_load(FILE *f); -void tg_save(tetris_game *obj, FILE *f); - -// Public methods not related to memory: -char tg_get(tetris_game *obj, int row, int col); -bool tg_check(tetris_game *obj, int row, int col); -bool tg_tick(tetris_game *obj, tetris_move move); -void tg_print(tetris_game *obj, FILE *f); - -#endif // TETRIS_H - - -#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) - -/******************************************************************************* - Array Definitions - *******************************************************************************/ - -tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = { - // I - {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, - {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, - {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, - {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, - // J - {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, - {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, - // L - {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, - {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, - // O - {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, - // S - {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, - {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, - {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, - // T - {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, - // Z - {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, - {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, -}; - -int GRAVITY_LEVEL[MAX_LEVEL+1] = { - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, - //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 -}; - -/******************************************************************************* - Helper Functions for Blocks - *******************************************************************************/ - -void sleep_milli(int milliseconds) -{ - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = milliseconds * 1000 * 1000; - nanosleep(&ts, NULL); -} - -/* - Return the block at the given row and column. - */ -char tg_get(tetris_game *obj, int row, int column) -{ - return obj->board[obj->cols * row + column]; -} - -/* - Set the block at the given row and column. - */ -static void tg_set(tetris_game *obj, int row, int column, char value) -{ - obj->board[obj->cols * row + column] = value; -} - -/* - Check whether a row and column are in bounds. - */ -bool tg_check(tetris_game *obj, int row, int col) -{ - return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; -} - -/* - Place a block onto the board. - */ -static void tg_put(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, - TYPE_TO_CELL(block.typ)); - } -} - -/* - Clear a block out of the board. - */ -static void tg_remove(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); - } -} - -/* - Check if a block can be placed on the board. - */ -static bool tg_fits(tetris_game *obj, tetris_block block) -{ - int i, r, c; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - r = block.loc.row + cell.row; - c = block.loc.col + cell.col; - if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { - return false; - } - } - return true; -} - -/* - Return a random tetromino type. - */ -static int random_tetromino(void) -{ - return rand() % NUM_TETROMINOS; -} - -/* - Create a new falling block and populate the next falling block with a random - one. - */ -static void tg_new_falling(tetris_game *obj) -{ - // Put in a new falling tetromino. - obj->falling = obj->next; - obj->next.typ = random_tetromino(); - obj->next.ori = 0; - obj->next.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; -} - -/******************************************************************************* - Game Turn Helpers - *******************************************************************************/ - -/* - Tick gravity, and move the block down if gravity should act. - */ -static void tg_do_gravity_tick(tetris_game *obj) -{ - obj->ticks_till_gravity--; - if (obj->ticks_till_gravity <= 0) { - tg_remove(obj, obj->falling); - obj->falling.loc.row++; - if (tg_fits(obj, obj->falling)) { - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - } else { - obj->falling.loc.row--; - tg_put(obj, obj->falling); - - tg_new_falling(obj); - } - tg_put(obj, obj->falling); - } -} - -/* - Move the falling tetris block left (-1) or right (+1). - */ -static void tg_move(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - obj->falling.loc.col += direction; - if (!tg_fits(obj, obj->falling)) { - obj->falling.loc.col -= direction; - } - tg_put(obj, obj->falling); -} - -/* - Send the falling tetris block to the bottom. - */ -static void tg_down(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - while (tg_fits(obj, obj->falling)) { - obj->falling.loc.row++; - } - obj->falling.loc.row--; - tg_put(obj, obj->falling); - tg_new_falling(obj); -} - -/* - Rotate the falling block in either direction (+/-1). - */ -static void tg_rotate(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - - while (true) { - obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; - - // If the new orientation fits, we're done. - if (tg_fits(obj, obj->falling)) - break; - - // Otherwise, try moving left to make it fit. - obj->falling.loc.col--; - if (tg_fits(obj, obj->falling)) - break; - - // Finally, try moving right to make it fit. - obj->falling.loc.col += 2; - if (tg_fits(obj, obj->falling)) - break; - - // Put it back in its original location and try the next orientation. - obj->falling.loc.col--; - // Worst case, we come back to the original orientation and it fits, so this - // loop will terminate. - } - - tg_put(obj, obj->falling); -} - -/* - Swap the falling block with the block in the hold buffer. - */ -static void tg_hold(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - if (obj->stored.typ == -1) { - obj->stored = obj->falling; - tg_new_falling(obj); - } else { - int typ = obj->falling.typ, ori = obj->falling.ori; - obj->falling.typ = obj->stored.typ; - obj->falling.ori = obj->stored.ori; - obj->stored.typ = typ; - obj->stored.ori = ori; - while (!tg_fits(obj, obj->falling)) { - obj->falling.loc.row--; - } - } - tg_put(obj, obj->falling); -} - -/* - Perform the action specified by the move. - */ -static void tg_handle_move(tetris_game *obj, tetris_move move) -{ - switch (move) { - case TM_LEFT: - tg_move(obj, -1); - break; - case TM_RIGHT: - tg_move(obj, 1); - break; - case TM_DROP: - tg_down(obj); - break; - case TM_CLOCK: - tg_rotate(obj, 1); - break; - case TM_COUNTER: - tg_rotate(obj, -1); - break; - case TM_HOLD: - tg_hold(obj); - break; - default: - // pass - break; - } -} - -/* - Return true if line i is full. - */ -static bool tg_line_full(tetris_game *obj, int i) -{ - int j; - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) - return false; - } - return true; -} - -/* - Shift every row above r down one. - */ -static void tg_shift_lines(tetris_game *obj, int r) -{ - int i, j; - for (i = r-1; i >= 0; i--) { - for (j = 0; j < obj->cols; j++) { - tg_set(obj, i+1, j, tg_get(obj, i, j)); - tg_set(obj, i, j, TC_EMPTY); - } - } -} - -/* - Find rows that are filled, remove them, shift, and return the number of - cleared rows. - */ -static int tg_check_lines(tetris_game *obj) -{ - int i, nlines = 0; - tg_remove(obj, obj->falling); // don't want to mess up falling block - - for (i = obj->rows-1; i >= 0; i--) { - if (tg_line_full(obj, i)) { - tg_shift_lines(obj, i); - i++; // do this line over again since they're shifted - nlines++; - } - } - - tg_put(obj, obj->falling); // replace - return nlines; -} - -/* - Adjust the score for the game, given how many lines were just cleared. - */ -static void tg_adjust_score(tetris_game *obj, int lines_cleared) -{ - static int line_multiplier[] = {0, 40, 100, 300, 1200}; - obj->points += line_multiplier[lines_cleared] * (obj->level + 1); - if (lines_cleared >= obj->lines_remaining) { - obj->level = MIN(MAX_LEVEL, obj->level + 1); - lines_cleared -= obj->lines_remaining; - obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; - } else { - obj->lines_remaining -= lines_cleared; - } -} - -/* - Return true if the game is over. - */ -static bool tg_game_over(tetris_game *obj) -{ - int i, j; - bool over = false; - tg_remove(obj, obj->falling); - for (i = 0; i < 2; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - over = true; + *cashoutp = 0; + return(0); } } - } - tg_put(obj, obj->falling); - return over; -} - -/******************************************************************************* - Main Public Functions - *******************************************************************************/ - -/* - Do a single game tick: process gravity, user input, and score. Return true if - the game is still running, false if it is over. - */ -bool tg_tick(tetris_game *obj, tetris_move move) -{ - int lines_cleared; - // Handle gravity. - tg_do_gravity_tick(obj); - - // Handle input. - tg_handle_move(obj, move); - - // Check for cleared lines - lines_cleared = tg_check_lines(obj); - - tg_adjust_score(obj, lines_cleared); - - // Return whether the game will continue (NOT whether it's over) - return !tg_game_over(obj); -} - -void tg_init(tetris_game *obj, int rows, int cols) -{ - // Initialization logic - obj->rows = rows; - obj->cols = cols; - obj->board = (char *)malloc(rows * cols); - memset(obj->board, TC_EMPTY, rows * cols); - obj->points = 0; - obj->level = 0; - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - obj->lines_remaining = LINES_PER_LEVEL; - srand(time(NULL)); - tg_new_falling(obj); - tg_new_falling(obj); - obj->stored.typ = -1; - obj->stored.ori = 0; - obj->stored.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; - printf("%d", obj->falling.loc.col); -} - -tetris_game *tg_create(int rows, int cols) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - tg_init(obj, rows, cols); - return obj; -} - -void tg_destroy(tetris_game *obj) -{ - // Cleanup logic - free(obj->board); -} - -void tg_delete(tetris_game *obj) { - tg_destroy(obj); - free(obj); -} - -/* - Load a game from a file. - */ -tetris_game *tg_load(FILE *f) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) - { - fprintf(stderr,"read game error\n"); - free(obj); - obj = 0; - } - else - { - obj->board = (char *)malloc(obj->rows * obj->cols); - if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) + if ( gametxid != prevgame ) { - fprintf(stderr,"fread error\n"); - free(obj->board); - free(obj); - obj = 0; + prevgame = gametxid; + bad++; + disp_gamesplayerdata(newdata); + disp_gamesplayerdata(playerdata); + fprintf(stderr,"%s playerdata: %s\n",gametxid.GetHex().c_str(),str); + fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,gamesaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); } } - return obj; -} - -/* - Save a game to a file. - */ -void tg_save(tetris_game *obj, FILE *f) -{ - if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) - fprintf(stderr,"error writing tetrisgame\n"); - else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - fprintf(stderr,"error writing board\n"); -} - -/* - Print a game board to a file. Really just for early debugging. - */ -void tg_print(tetris_game *obj, FILE *f) { - int i, j; - for (i = 0; i < obj->rows; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) { - fputs(TC_EMPTY_STR, f); - } else { - fputs(TC_BLOCK_STR, f); - } - } - fputc('\n', f); - } -} - -/* - 2 columns per cell makes the game much nicer. - */ -#define COLS_PER_CELL 2 -/* - Macro to print a cell of a specific type to a window. - */ -#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ -waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) -#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') - -/* - Print the tetris board onto the ncurses window. - */ -void display_board(WINDOW *w, tetris_game *obj) -{ - int i, j; - box(w, 0, 0); - for (i = 0; i < obj->rows; i++) { - wmove(w, 1 + i, 1); - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - ADD_BLOCK(w,tg_get(obj, i, j)); - } else { - ADD_EMPTY(w); - } - } - } - wnoutrefresh(w); -} - -/* - Display a tetris piece in a dedicated window. - */ -void display_piece(WINDOW *w, tetris_block block) -{ - int b; - tetris_location c; - wclear(w); - box(w, 0, 0); - if (block.typ == -1) { - wnoutrefresh(w); - return; - } - for (b = 0; b < TETRIS; b++) { - c = TETROMINOS[block.typ][block.ori][b]; - wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); - ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); - } - wnoutrefresh(w); -} - -/* - Display score information in a dedicated window. - */ -void display_score(WINDOW *w, tetris_game *tg) -{ - wclear(w); - box(w, 0, 0); - wprintw(w, (char *)"Score\n%d\n", tg->points); - wprintw(w, (char *)"Level\n%d\n", tg->level); - wprintw(w, (char *)"Lines\n%d\n", tg->lines_remaining); - wnoutrefresh(w); -} - -/* - Save and exit the game. - */ -void save(tetris_game *game, WINDOW *w) -{ - FILE *f; - - wclear(w); - box(w, 0, 0); // return the border - wmove(w, 1, 1); - wprintw(w, (char *)"Save and exit? [Y/n] "); - wrefresh(w); - timeout(-1); - if (getch() == 'n') { - timeout(0); - return; - } - f = fopen("tetris.save", "w"); - tg_save(game, f); - fclose(f); - tg_delete(game); - endwin(); - fprintf(stderr,"Game saved to \"tetris.save\".\n"); - fprintf(stderr,"Resume by passing the filename as an argument to this program.\n"); - exit(EXIT_SUCCESS); -} - -/* - Do the NCURSES initialization steps for color blocks. - */ -void init_colors(void) -{ - start_color(); - //init_color(COLOR_ORANGE, 1000, 647, 0); - init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); - init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); - init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); - init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); - init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); - init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); - init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); -} - -/* - Main tetris game! - */ -#ifdef STANDALONE -char *clonestr(char *str) -{ - char *clone; int32_t len; - if ( str == 0 || str[0] == 0 ) - { - printf("warning cloning nullstr.%p\n",str); -#ifdef __APPLE__ - while ( 1 ) sleep(1); -#endif - str = (char *)""; - } - len = strlen(str); - clone = (char *)calloc(1,len+16); - strcpy(clone,str); - return(clone); -} - -int tetris(int argc, char **argv) -{ - tetris_game *tg; - tetris_move move = TM_NONE; - bool running = true; - WINDOW *board, *next, *hold, *score; - int32_t c,skipcount=0; bits256 gametxid; uint32_t eventid = 0; - memset(&gametxid,0,sizeof(gametxid)); - // Load file if given a filename. - if (argc >= 2) { - FILE *f = fopen(argv[1], "r"); - if (f == NULL) { - perror("tetris"); - exit(EXIT_FAILURE); - } - tg = tg_load(f); - fclose(f); - } else { - // Otherwise create new game. - tg = tg_create(22, 10); - } - // NCURSES initialization: - initscr(); // initialize curses - cbreak(); // pass key presses to program, but not signals - noecho(); // don't echo key presses to screen - keypad(stdscr, TRUE); // allow arrow keys - timeout(0); // no blocking on getch() - curs_set(0); // set the cursor to invisible - init_colors(); // setup tetris colors - - // Create windows for each section of the interface. - board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); - next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); - hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); - score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); - int32_t counter = 0; - // Game loop - while (running) { - running = tg_tick(tg, move); - display_board(board, tg); - display_piece(next, tg->next); - display_piece(hold, tg->stored); - display_score(score, tg); - if ( (counter++ % 5) == 0 ) - doupdate(); - sleep_milli(10); - c = getch(); - if ( c != -1 || skipcount == 0x3fff ) - { - if ( skipcount > 0 ) - issue_games_events(gametxid,eventid-skipcount,skipcount | 0x4000); - if ( c != -1 ) - issue_games_events(gametxid,eventid,c); - skipcount = 0; - } else skipcount++; - eventid++; - switch ( c ) - { - case KEY_LEFT: - move = TM_LEFT; - break; - case KEY_RIGHT: - move = TM_RIGHT; - break; - case KEY_UP: - move = TM_CLOCK; - break; - case KEY_DOWN: - move = TM_DROP; - break; - case 'q': - running = false; - move = TM_NONE; - break; - case 'p': - wclear(board); - box(board, 0, 0); - wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); - wprintw(board, "PAUSED"); - wrefresh(board); - timeout(-1); - getch(); - timeout(0); - move = TM_NONE; - break; - case 's': - save(tg, board); - move = TM_NONE; - break; - case ' ': - move = TM_HOLD; - break; - default: - move = TM_NONE; - } - } - - // Deinitialize NCurses - wclear(stdscr); - endwin(); - // Output ending message. - printf("Game over!\n"); - printf("You finished with %d points on level %d.\n", tg->points, tg->level); - - // Deinitialize Tetris - tg_delete(tg); - return 0; -} - -int32_t games_replay(uint64_t seed,int32_t sleeptime) -{ + sprintf(fname,"%s.%llu.pack",GAMENAME,(long long)seed); + remove(fname); + //fprintf(stderr,"no keys games_extractgame %s\n",gametxid.GetHex().c_str()); return(-1); } #endif + diff --git a/src/cc/gamescc.h b/src/cc/gamescc.h index 19e5f8d26..b804216d7 100644 --- a/src/cc/gamescc.h +++ b/src/cc/gamescc.h @@ -3,6 +3,9 @@ #include #include +#define GAMES_RNGMULT 11109 +#define GAMES_RNGOFFSET 13849 +#define GAMES_MAXRNGS 10000 #ifndef STANDALONE @@ -12,7 +15,6 @@ extern CWallet* pwalletMain; #include "CCinclude.h" #include "secp256k1.h" -std::string MYCCLIBNAME = (char *)"gamescc"; #define EVAL_GAMES (EVAL_FAUCET2+1) #define GAMES_TXFEE 10000 @@ -20,20 +22,17 @@ std::string MYCCLIBNAME = (char *)"gamescc"; #define GAMES_MAXKEYSTROKESGAP 60 #define GAMES_MAXPLAYERS 64 #define GAMES_REGISTRATIONSIZE (100 * 10000) -#define GAMES_REGISTRATION 5 +#define GAMES_REGISTRATION 1 -#define GAMES_RNGMULT 11109 -#define GAMES_RNGOFFSET 13849 -#define GAMES_MAXRNGS 10000 #define MYCCNAME "games" std::string Games_pname; -#define GAMENAME "sudoku" #define RPC_FUNCS \ { (char *)MYCCNAME, (char *)"rng", (char *)"hash,playerid", 1, 2, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"rngnext", (char *)"seed", 1, 1, ' ', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"fund", (char *)"amount", 1, 1, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"players", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"games", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"pending", (char *)"no params", 0, 0, ' ', EVAL_GAMES }, \ @@ -42,14 +41,18 @@ std::string Games_pname; { (char *)MYCCNAME, (char *)"playerinfo", (char *)"playertxid", 1, 1, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"gameinfo", (char *)"gametxid", 1, 1, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"keystrokes", (char *)"txid,hexstr", 2, 2, 'K', EVAL_GAMES }, \ - { (char *)MYCCNAME, (char *)"finish", (char *)"gametxid", 1, 1, 'Q', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"bailout", (char *)"gametxid", 1, 1, 'Q', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"events", (char *)"eventshex [gametxid [eventid]]", 1, 3, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, ' ', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"bet", (char *)"amount hexstr", 2, 2, ' ', EVAL_GAMES }, \ + { (char *)MYCCNAME, (char *)"settle", (char *)"height", 1, 1, ' ', EVAL_GAMES }, \ { (char *)MYCCNAME, (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_GAMES }, bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx); UniValue games_rng(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_rngnext(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_fund(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); @@ -58,10 +61,13 @@ UniValue games_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); -UniValue games_finish(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_events(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); UniValue games_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); +UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params); #define CUSTOM_DISPATCH \ if ( cp->evalcode == EVAL_GAMES ) \ @@ -92,45 +98,23 @@ if ( cp->evalcode == EVAL_GAMES ) \ return(games_keystrokes(txfee,cp,params)); \ else if ( strcmp(method,"extract") == 0 ) \ return(games_extract(txfee,cp,params)); \ - else if ( strcmp(method,"finish") == 0 ) \ - return(games_finish(txfee,cp,params)); \ + else if ( strcmp(method,"bailout") == 0 ) \ + return(games_bailout(txfee,cp,params)); \ + else if ( strcmp(method,"highlander") == 0 ) \ + return(games_highlander(txfee,cp,params)); \ + else if ( strcmp(method,"fund") == 0 ) \ + return(games_fund(txfee,cp,params)); \ + else if ( strcmp(method,"bet") == 0 ) \ + return(games_bet(txfee,cp,params)); \ + else if ( strcmp(method,"settle") == 0 ) \ + return(games_settle(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); \ } \ } #endif -#define MAXPACK 23 -struct games_packitem -{ - int32_t type,launch,count,which,hplus,dplus,arm,flags,group; - char damage[8],hurldmg[8]; -}; - -struct games_player -{ - int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,amulet; - struct games_packitem gamespack[MAXPACK]; -}; - -struct games_state -{ - uint64_t seed; - char *keystrokes,*keystrokeshex; - uint32_t needflush,replaydone; - int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring,lastnum; - FILE *logfp; - struct games_player P; - char buffered[10000]; - uint8_t playerdata[10000]; -}; - -int32_t games_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct games_player *player,int32_t sleepmillis); -void games_packitemstr(char *packitemstr,struct games_packitem *item); - - #endif diff --git a/src/cc/makecclib b/src/cc/makecclib index adac757c3..b2f8e2ee1 100755 --- a/src/cc/makecclib +++ b/src/cc/makecclib @@ -1,2 +1,19 @@ #!/bin/sh -gcc -O3 -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 ../libcc.so cclib.cpp +rm *.so rogue/rogue games/tetris games/prices + +echo rogue +make -f Makefile_rogue +./makerogue + +echo sudoku/musig/dilithium +gcc -O3 -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 sudokucc.so cclib.cpp + +echo games tetris +./maketetris + +echo games prices +./makeprices + +echo customcc stub +gcc -O3 -DBUILD_CUSTOMCC -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 customcc.so cclib.cpp + diff --git a/src/cc/makeprices b/src/cc/makeprices new file mode 100755 index 000000000..2779c1c5b --- /dev/null +++ b/src/cc/makeprices @@ -0,0 +1,8 @@ +echo pricescc.so +gcc -O3 -DBUILD_GAMESCC -DBUILD_PRICES -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 pricescc.so cclib.cpp +echo prices +cd games +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE -DBUILD_PRICES ../gamescc.cpp -lncurses -lcurl -o prices +cd .. + + diff --git a/src/cc/maketetris b/src/cc/maketetris index 9f0af354e..c39536229 100755 --- a/src/cc/maketetris +++ b/src/cc/maketetris @@ -1,2 +1,7 @@ -gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE gamescc.cpp -lncurses -lcurl -o tetris +echo gamescc.so with tetris +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 +echo tetris dapp +cd games +gcc -O3 -std=c++11 -I../secp256k1/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -DSTANDALONE ../gamescc.cpp -lncurses -lcurl -o tetris +cd .. diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 184c92d33..e0c4c8ada 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -192,7 +192,9 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & if ( tmptx.vout.size() > 0 && DecodePaymentsOpRet(tmptx.vout[tmptx.vout.size()-1].scriptPubKey,lockedblocks,minrelease,totalallocations,txidoprets) != 0 ) { if ( lockedblocks < 0 || minrelease < 0 || totalallocations <= 0 || txidoprets.size() < 2 ) - return(eval->Invalid("negative values")); + return(eval->Invalid("negative values")); + if ( !CheckTxFee(tx, PAYMENTS_TXFEE, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + return eval->Invalid("txfee is too high"); Paymentspk = GetUnspendable(cp,0); //fprintf(stderr, "lockedblocks.%i minrelease.%i totalallocations.%i txidopret1.%s txidopret2.%s\n",lockedblocks, minrelease, totalallocations, txidoprets[0].ToString().c_str(), txidoprets[1].ToString().c_str() ); @@ -281,7 +283,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); return(eval->Invalid("vin is not paymentsCC type")); } //else fprintf(stderr, "vin.%i opret type txid.%s\n", i, txin.GetHash().ToString().c_str()); - } + } // check the chain depth vs locked blcoks requirement. CBlockIndex* pblockindex = mapBlockIndex[blockhash]; if ( pblockindex->GetHeight() > ht-lockedblocks ) diff --git a/src/cc/prices.cpp b/src/cc/prices.cpp index c53207562..1ab5aa1cb 100644 --- a/src/cc/prices.cpp +++ b/src/cc/prices.cpp @@ -451,4 +451,3 @@ std::string PricesFinish(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid, } - diff --git a/src/cc/rewards.cpp b/src/cc/rewards.cpp index 65e32ee27..73f723453 100644 --- a/src/cc/rewards.cpp +++ b/src/cc/rewards.cpp @@ -197,9 +197,6 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t uint256 txid,fundingtxid,hashBlock,vinfundingtxid; uint64_t vinsbits,sbits,APR,minseconds,maxseconds,mindeposit,amount,reward,txfee=10000; int32_t numvins,numvouts,preventCCvins,preventCCvouts,i; uint8_t funcid; CScript scriptPubKey; CTransaction fundingTx,vinTx; numvins = tx.vin.size(); numvouts = tx.vout.size(); - int64_t interest; uint64_t valuein; - CCoinsViewCache &view = *pcoinsTip; - valuein = view.GetValueIn(chainActive.LastTip()->GetHeight(),&interest,tx,chainActive.LastTip()->nTime); preventCCvins = preventCCvouts = -1; if ( numvouts < 1 ) return eval->Invalid("no vouts"); @@ -258,20 +255,22 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t if ( (*cp->ismyvin)(tx.vin[i].scriptSig) == 0 ) return eval->Invalid("unexpected normal vin for unlock"); } - if ( valuein-tx.GetValueOut() > txfee ) + if ( !CheckTxFee(tx, txfee, chainActive.LastTip()->GetHeight(), chainActive.LastTip()->nTime) ) + return eval->Invalid("txfee is too high"); + reward = RewardsCalc(amount,tx.vin[0].prevout.hash,APR,minseconds,maxseconds,mindeposit); + if ( numvins == 1 && tx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 ) { - fprintf(stderr, "valueout.%li vs valuein.%li txfee.%li\n", tx.GetValueOut(), valuein, txfee); - return eval->Invalid("alright is stealing your money"); - } - if ( numvouts == 2 && numvins == 1 ) - { - if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 ) - return eval->Invalid("unlock recover tx vout.0 is not normal output"); + if ( reward == 0 ) + return eval->Invalid("unlock recover no rewards"); + else if ( tx.vout[1].nValue != 10000 ) + return eval->Invalid("wrong marker vour value"); + else if ( tx.vout[1].scriptPubKey != tx.vout[0].scriptPubKey ) + return eval->Invalid("unlock recover tx vout.1 mismatched scriptPubKey"); else if ( tx.vout[0].scriptPubKey != vinTx.vout[1].scriptPubKey ) return eval->Invalid("unlock recover tx vout.0 mismatched scriptPubKey"); else if ( tx.vout[0].nValue > vinTx.vout[0].nValue ) return eval->Invalid("unlock recover tx vout.0 mismatched amounts"); - else if ( tx.vout[1].nValue > 0 ) + else if ( tx.vout[2].nValue > 0 ) return eval->Invalid("unlock recover tx vout.1 nonz amount"); else return(true); } @@ -689,8 +688,7 @@ std::string RewardsUnlock(uint64_t txfee,char *planstr,uint256 fundingtxid,uint2 } else { - firstmtx.vout.push_back(CTxOut(amount-txfee,scriptPubKey)); - //CCerror = "cant find enough rewards inputs"; + firstmtx.vout.push_back(CTxOut(amount-txfee*2,scriptPubKey)); fprintf(stderr,"not enough rewards funds to payout %.8f, recover mode tx\n",(double)(reward+txfee)/COIN); return(FinalizeCCTx(-1LL,cp,firstmtx,mypk,txfee,EncodeRewardsOpRet('U',sbits,fundingtxid))); } diff --git a/src/cc/rogue/cursesd.h b/src/cc/rogue/cursesd.h index e3eec5d41..7dd83d435 100644 --- a/src/cc/rogue/cursesd.h +++ b/src/cc/rogue/cursesd.h @@ -16,6 +16,13 @@ #ifndef H_CURSESD_H #define H_CURSESD_H +#define KEY_OFFSET 0x100 +#define KEY_DOWN (KEY_OFFSET + 0x02) /* Down arrow key */ +#define KEY_UP (KEY_OFFSET + 0x03) /* Up arrow key */ +#define KEY_LEFT (KEY_OFFSET + 0x04) /* Left arrow key */ +#define KEY_RIGHT (KEY_OFFSET + 0x05) /* Right arrow key */ + + #define COLOR_BLACK 0 #ifdef PDC_RGB /* RGB */ @@ -168,6 +175,8 @@ char *unctrl(char c); #define leaveok(win,bf) 0 #define halfdelay(x) 0 #define nocbreak() 0 +#define cbreak() 0 +#define curs_set(x) 0 // for tetris #define init_pair(a,b,c) 0 diff --git a/src/cc/rogue_rpc.cpp b/src/cc/rogue_rpc.cpp index ee5f3d566..c5350a68d 100644 --- a/src/cc/rogue_rpc.cpp +++ b/src/cc/rogue_rpc.cpp @@ -283,6 +283,24 @@ int32_t rogue_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx, return(0); } +int64_t rogue_buyins(uint256 gametxid,int32_t maxplayers) +{ + int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; int64_t buyins = 0; + for (i=0; i= 0 ) + { + if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) + { + if ( spenttx.vout[0].nValue > ROGUE_REGISTRATIONSIZE ) + buyins += (spenttx.vout[0].nValue - ROGUE_REGISTRATIONSIZE); + } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); + } //else fprintf(stderr,"vout %d is unspent\n",vout); + } + return(buyins); +} + int32_t rogue_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0) { uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey roguepk; uint64_t txfee = 10000; @@ -690,6 +708,7 @@ uint64_t rogue_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 obj.push_back(Pair("alive",rogue_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); obj.push_back(Pair("openslots",openslots)); obj.push_back(Pair("numplayers",numplayers)); + obj.push_back(Pair("buyins",ValueFromAmount(rogue_buyins(gametxid,maxplayers)))); } obj.push_back(Pair("maxplayers",maxplayers)); obj.push_back(Pair("buyin",ValueFromAmount(buyin))); @@ -1093,6 +1112,20 @@ UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) return(result); } +int64_t rogue_cashout(struct rogue_player *P) +{ + int32_t dungeonlevel; int64_t cashout,mult = 10; + if ( P->amulet != 0 ) + mult *= 5; + dungeonlevel = P->dungeonlevel; + if ( P->amulet != 0 && dungeonlevel < 26 ) + dungeonlevel = 26; + if ( dungeonlevel > 42 ) + dungeonlevel = 42; + cashout = (uint64_t)P->gold * P->gold * mult * dungeonlevel; + return(cashout); +} + int32_t rogue_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct CCcontract_info *cp,std::vector playerdata,uint256 gametxid,CPubKey pk) { static uint32_t good,bad; static uint256 prevgame; @@ -1105,17 +1138,9 @@ int32_t rogue_playerdata_validate(int64_t *cashoutp,uint256 &playertxid,struct C free(keystrokes); sprintf(fname,"rogue.%llu.pack",(long long)seed); remove(fname); - for (i=0; i 42 ) - dungeonlevel = 42; - *cashoutp = (uint64_t)P.gold * P.gold * mult * dungeonlevel; + *cashoutp = rogue_cashout(&P); if ( newdata == playerdata ) { if ( gametxid != prevgame ) @@ -1206,16 +1231,10 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param result.push_back(Pair("name","rogue")); result.push_back(Pair("method",method)); result.push_back(Pair("myrogueaddr",myrogueaddr)); + mult = 10; //100000; if ( strcmp(method,"bailout") == 0 ) - { funcid = 'Q'; - mult = 10; //100000; - } - else - { - funcid = 'H'; - mult = 20; //200000; - } + else funcid = 'H'; if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) { if ( n > 0 ) @@ -1264,13 +1283,10 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param cpTokens = CCinit(&tokensC, EVAL_TOKENS); mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); - if ( P.amulet != 0 ) - mult *= 5; - dungeonlevel = P.dungeonlevel; - if ( P.amulet != 0 && dungeonlevel < 26 ) - dungeonlevel = 26; - cashout = (uint64_t)P.gold * P.gold * mult * dungeonlevel; + cashout = rogue_cashout(&P); fprintf(stderr,"\nextracted $$$gold.%d -> %.8f ROGUE hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); + if ( komodo_nextheight() > 77777 && cashout > ROGUE_MAXCASHOUT ) + cashout = ROGUE_MAXCASHOUT; if ( funcid == 'H' && maxplayers > 1 ) { if ( P.amulet == 0 ) @@ -1280,12 +1296,11 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param else if ( rogue_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) return(cclib_error(result,"highlander must be a winner or last one standing")); } + cashout *= 2; cashout += numplayers * buyin; } if ( cashout > 0 ) { - if ( komodo_nextheight() > 77777 && cashout > ROGUE_MAXCASHOUT ) - cashout = ROGUE_MAXCASHOUT; if ( (inputsum= AddCClibInputs(cp,mtx,roguepk,cashout,60,cp->unspendableCCaddr)) > cashout ) CCchange = (inputsum - cashout); else fprintf(stderr,"couldnt find enough utxos\n"); @@ -1326,12 +1341,12 @@ UniValue rogue_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *param UniValue rogue_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - return(rogue_finishgame(txfee,cp,params,"bailout")); + return(rogue_finishgame(txfee,cp,params,(char *)"bailout")); } UniValue rogue_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) { - return(rogue_finishgame(txfee,cp,params,"highlander")); + return(rogue_finishgame(txfee,cp,params,(char *)"highlander")); } UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) @@ -1506,7 +1521,7 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C if ( (numvouts= tx.vout.size()) > 1 ) { txid = tx.GetHash(); - if ( txid == Parseuint256("1ae04dc0c5f2fca2053819a3a1b2efe5d355c34f58d6f16d59e5e2573e7baf7f") ) // osx rogue chain ht.50902 + if ( txid == Parseuint256("1ae04dc0c5f2fca2053819a3a1b2efe5d355c34f58d6f16d59e5e2573e7baf7f") || txid == Parseuint256("2a34b36cc1292aecfaabdad79b42cab9989fa6dcc87ac8ca88aa6162dab1e2c4") ) // osx rogue chain ht.50902, 69522 enabled = 0; scriptPubKey = tx.vout[numvouts-1].scriptPubKey; GetOpReturnData(scriptPubKey,vopret); @@ -1598,13 +1613,13 @@ bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C if ( enabled != 0 ) return eval->Invalid("mismatched playerdata"); } + if ( height > 777777 && cashout > ROGUE_MAXCASHOUT ) + cashout = ROGUE_MAXCASHOUT; if ( funcid == 'H' ) { cashout *= 2; - //cashout += numplayers * buyin; + cashout += rogue_buyins(gametxid,maxplayers); } - if ( height > 777777 && cashout > ROGUE_MAXCASHOUT ) - cashout = ROGUE_MAXCASHOUT; sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d txid.%s %.8f vs vout2 %.8f",tokentx,decoded,height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); if ( strcmp(laststr,cashstr) != 0 ) { diff --git a/src/cc/tetris.cpp b/src/cc/tetris.cpp deleted file mode 100644 index d6ae473fe..000000000 --- a/src/cc/tetris.cpp +++ /dev/null @@ -1,2411 +0,0 @@ - -/***************************************************************************/ -/** https://github.com/brenns10/tetris - @file main.c - @author Stephen Brennan - @date Created Wednesday, 10 June 2015 - @brief Main program for tetris. - @copyright Copyright (c) 2015, Stephen Brennan. Released under the Revised - BSD License. See LICENSE.txt for details. - *******************************************************************************/ - - -#ifndef TETRIS_H -#define TETRIS_H - -#include // for FILE -#include // for bool -#include -#include -#include -#include -#include - -#include -#include - -//#include -//#include - - -/* - Convert a tetromino type to its corresponding cell. - */ -#define TYPE_TO_CELL(x) ((x)+1) - -/* - Strings for how you would print a tetris board. - */ -#define TC_EMPTY_STR " " -#define TC_BLOCK_STR "\u2588" - -/* - Questions about a tetris cell. - */ -#define TC_IS_EMPTY(x) ((x) == TC_EMPTY) -#define TC_IS_FILLED(x) (!TC_IS_EMPTY(x)) - -/* - How many cells in a tetromino? - */ -#define TETRIS 4 -/* - How many tetrominos? - */ -#define NUM_TETROMINOS 7 -/* - How many orientations of a tetromino? - */ -#define NUM_ORIENTATIONS 4 - -/* - Level constants. - */ -#define MAX_LEVEL 19 -#define LINES_PER_LEVEL 10 - -/* - A "cell" is a 1x1 block within a tetris board. - */ -typedef enum { - TC_EMPTY, TC_CELLI, TC_CELLJ, TC_CELLL, TC_CELLO, TC_CELLS, TC_CELLT, TC_CELLZ -} tetris_cell; - -/* - A "type" is a type/shape of a tetromino. Not including orientation. - */ -typedef enum { - TET_I, TET_J, TET_L, TET_O, TET_S, TET_T, TET_Z -} tetris_type; - -/* - A row,column pair. Negative numbers allowed, because we need them for - offsets. - */ -typedef struct { - int row; - int col; -} tetris_location; - -/* - A "block" is a struct that contains information about a tetromino. - Specifically, what type it is, what orientation it has, and where it is. - */ -typedef struct { - int typ; - int ori; - tetris_location loc; -} tetris_block; - -/* - All possible moves to give as input to the game. - */ -typedef enum { - TM_LEFT, TM_RIGHT, TM_CLOCK, TM_COUNTER, TM_DROP, TM_HOLD, TM_NONE -} tetris_move; - -/* - A game object! - */ -typedef struct { - /* - Game board stuff: - */ - int rows; - int cols; - char *board; - /* - Scoring information: - */ - int points; - int level; - /* - Falling block is the one currently going down. Next block is the one that - will be falling after this one. Stored is the block that you can swap out. - */ - tetris_block falling; - tetris_block next; - tetris_block stored; - /* - Number of game ticks until the block will move down. - */ - int ticks_till_gravity; - /* - Number of lines until you advance to the next level. - */ - int lines_remaining; -} tetris_game; - -/* - This array stores all necessary information about the cells that are filled by - each tetromino. The first index is the type of the tetromino (i.e. shape, - e.g. I, J, Z, etc.). The next index is the orientation (0-3). The final - array contains 4 tetris_location objects, each mapping to an offset from a - point on the upper left that is the tetromino "origin". - */ -extern tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS]; - -/* - This array tells you how many ticks per gravity by level. Decreases as level - increases, to add difficulty. - */ -extern int GRAVITY_LEVEL[MAX_LEVEL+1]; - -// Data structure manipulation. -void tg_init(tetris_game *obj, int rows, int cols); -tetris_game *tg_create(int rows, int cols); -void tg_destroy(tetris_game *obj); -void tg_delete(tetris_game *obj); -tetris_game *tg_load(FILE *f); -void tg_save(tetris_game *obj, FILE *f); - -// Public methods not related to memory: -char tg_get(tetris_game *obj, int row, int col); -bool tg_check(tetris_game *obj, int row, int col); -bool tg_tick(tetris_game *obj, tetris_move move); -void tg_print(tetris_game *obj, FILE *f); - -#endif // TETRIS_H - - -#define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) -#define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) - -/******************************************************************************* - Array Definitions - *******************************************************************************/ - -tetris_location TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = { - // I - {{{1, 0}, {1, 1}, {1, 2}, {1, 3}}, - {{0, 2}, {1, 2}, {2, 2}, {3, 2}}, - {{3, 0}, {3, 1}, {3, 2}, {3, 3}}, - {{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, - // J - {{{0, 0}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 2}}, - {{0, 1}, {1, 1}, {2, 0}, {2, 1}}}, - // L - {{{0, 2}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {2, 1}, {2, 2}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 0}}, - {{0, 0}, {0, 1}, {1, 1}, {2, 1}}}, - // O - {{{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}, - {{0, 1}, {0, 2}, {1, 1}, {1, 2}}}, - // S - {{{0, 1}, {0, 2}, {1, 0}, {1, 1}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 2}}, - {{1, 1}, {1, 2}, {2, 0}, {2, 1}}, - {{0, 0}, {1, 0}, {1, 1}, {2, 1}}}, - // T - {{{0, 1}, {1, 0}, {1, 1}, {1, 2}}, - {{0, 1}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {1, 2}, {2, 1}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 1}}}, - // Z - {{{0, 0}, {0, 1}, {1, 1}, {1, 2}}, - {{0, 2}, {1, 1}, {1, 2}, {2, 1}}, - {{1, 0}, {1, 1}, {2, 1}, {2, 2}}, - {{0, 1}, {1, 0}, {1, 1}, {2, 0}}}, -}; - -int GRAVITY_LEVEL[MAX_LEVEL+1] = { - // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, - //10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 30, 28, 26, 24, 22, 20, 16, 12, 8, 4 -}; - -/******************************************************************************* - Helper Functions for Blocks - *******************************************************************************/ - -void sleep_milli(int milliseconds) -{ - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = milliseconds * 1000 * 1000; - nanosleep(&ts, NULL); -} - -/* - Return the block at the given row and column. - */ -char tg_get(tetris_game *obj, int row, int column) -{ - return obj->board[obj->cols * row + column]; -} - -/* - Set the block at the given row and column. - */ -static void tg_set(tetris_game *obj, int row, int column, char value) -{ - obj->board[obj->cols * row + column] = value; -} - -/* - Check whether a row and column are in bounds. - */ -bool tg_check(tetris_game *obj, int row, int col) -{ - return 0 <= row && row < obj->rows && 0 <= col && col < obj->cols; -} - -/* - Place a block onto the board. - */ -static void tg_put(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, - TYPE_TO_CELL(block.typ)); - } -} - -/* - Clear a block out of the board. - */ -static void tg_remove(tetris_game *obj, tetris_block block) -{ - int i; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - tg_set(obj, block.loc.row + cell.row, block.loc.col + cell.col, TC_EMPTY); - } -} - -/* - Check if a block can be placed on the board. - */ -static bool tg_fits(tetris_game *obj, tetris_block block) -{ - int i, r, c; - for (i = 0; i < TETRIS; i++) { - tetris_location cell = TETROMINOS[block.typ][block.ori][i]; - r = block.loc.row + cell.row; - c = block.loc.col + cell.col; - if (!tg_check(obj, r, c) || TC_IS_FILLED(tg_get(obj, r, c))) { - return false; - } - } - return true; -} - -/* - Return a random tetromino type. - */ -static int random_tetromino(void) { - return rand() % NUM_TETROMINOS; -} - -/* - Create a new falling block and populate the next falling block with a random - one. - */ -static void tg_new_falling(tetris_game *obj) -{ - // Put in a new falling tetromino. - obj->falling = obj->next; - obj->next.typ = random_tetromino(); - obj->next.ori = 0; - obj->next.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; -} - -/******************************************************************************* - Game Turn Helpers - *******************************************************************************/ - -/* - Tick gravity, and move the block down if gravity should act. - */ -static void tg_do_gravity_tick(tetris_game *obj) -{ - obj->ticks_till_gravity--; - if (obj->ticks_till_gravity <= 0) { - tg_remove(obj, obj->falling); - obj->falling.loc.row++; - if (tg_fits(obj, obj->falling)) { - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - } else { - obj->falling.loc.row--; - tg_put(obj, obj->falling); - - tg_new_falling(obj); - } - tg_put(obj, obj->falling); - } -} - -/* - Move the falling tetris block left (-1) or right (+1). - */ -static void tg_move(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - obj->falling.loc.col += direction; - if (!tg_fits(obj, obj->falling)) { - obj->falling.loc.col -= direction; - } - tg_put(obj, obj->falling); -} - -/* - Send the falling tetris block to the bottom. - */ -static void tg_down(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - while (tg_fits(obj, obj->falling)) { - obj->falling.loc.row++; - } - obj->falling.loc.row--; - tg_put(obj, obj->falling); - tg_new_falling(obj); -} - -/* - Rotate the falling block in either direction (+/-1). - */ -static void tg_rotate(tetris_game *obj, int direction) -{ - tg_remove(obj, obj->falling); - - while (true) { - obj->falling.ori = (obj->falling.ori + direction) % NUM_ORIENTATIONS; - - // If the new orientation fits, we're done. - if (tg_fits(obj, obj->falling)) - break; - - // Otherwise, try moving left to make it fit. - obj->falling.loc.col--; - if (tg_fits(obj, obj->falling)) - break; - - // Finally, try moving right to make it fit. - obj->falling.loc.col += 2; - if (tg_fits(obj, obj->falling)) - break; - - // Put it back in its original location and try the next orientation. - obj->falling.loc.col--; - // Worst case, we come back to the original orientation and it fits, so this - // loop will terminate. - } - - tg_put(obj, obj->falling); -} - -/* - Swap the falling block with the block in the hold buffer. - */ -static void tg_hold(tetris_game *obj) -{ - tg_remove(obj, obj->falling); - if (obj->stored.typ == -1) { - obj->stored = obj->falling; - tg_new_falling(obj); - } else { - int typ = obj->falling.typ, ori = obj->falling.ori; - obj->falling.typ = obj->stored.typ; - obj->falling.ori = obj->stored.ori; - obj->stored.typ = typ; - obj->stored.ori = ori; - while (!tg_fits(obj, obj->falling)) { - obj->falling.loc.row--; - } - } - tg_put(obj, obj->falling); -} - -/* - Perform the action specified by the move. - */ -static void tg_handle_move(tetris_game *obj, tetris_move move) -{ - switch (move) { - case TM_LEFT: - tg_move(obj, -1); - break; - case TM_RIGHT: - tg_move(obj, 1); - break; - case TM_DROP: - tg_down(obj); - break; - case TM_CLOCK: - tg_rotate(obj, 1); - break; - case TM_COUNTER: - tg_rotate(obj, -1); - break; - case TM_HOLD: - tg_hold(obj); - break; - default: - // pass - break; - } -} - -/* - Return true if line i is full. - */ -static bool tg_line_full(tetris_game *obj, int i) -{ - int j; - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) - return false; - } - return true; -} - -/* - Shift every row above r down one. - */ -static void tg_shift_lines(tetris_game *obj, int r) -{ - int i, j; - for (i = r-1; i >= 0; i--) { - for (j = 0; j < obj->cols; j++) { - tg_set(obj, i+1, j, tg_get(obj, i, j)); - tg_set(obj, i, j, TC_EMPTY); - } - } -} - -/* - Find rows that are filled, remove them, shift, and return the number of - cleared rows. - */ -static int tg_check_lines(tetris_game *obj) -{ - int i, nlines = 0; - tg_remove(obj, obj->falling); // don't want to mess up falling block - - for (i = obj->rows-1; i >= 0; i--) { - if (tg_line_full(obj, i)) { - tg_shift_lines(obj, i); - i++; // do this line over again since they're shifted - nlines++; - } - } - - tg_put(obj, obj->falling); // replace - return nlines; -} - -/* - Adjust the score for the game, given how many lines were just cleared. - */ -static void tg_adjust_score(tetris_game *obj, int lines_cleared) -{ - static int line_multiplier[] = {0, 40, 100, 300, 1200}; - obj->points += line_multiplier[lines_cleared] * (obj->level + 1); - if (lines_cleared >= obj->lines_remaining) { - obj->level = MIN(MAX_LEVEL, obj->level + 1); - lines_cleared -= obj->lines_remaining; - obj->lines_remaining = LINES_PER_LEVEL - lines_cleared; - } else { - obj->lines_remaining -= lines_cleared; - } -} - -/* - Return true if the game is over. - */ -static bool tg_game_over(tetris_game *obj) -{ - int i, j; - bool over = false; - tg_remove(obj, obj->falling); - for (i = 0; i < 2; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - over = true; - } - } - } - tg_put(obj, obj->falling); - return over; -} - -/******************************************************************************* - Main Public Functions - *******************************************************************************/ - -/* - Do a single game tick: process gravity, user input, and score. Return true if - the game is still running, false if it is over. - */ -bool tg_tick(tetris_game *obj, tetris_move move) -{ - int lines_cleared; - // Handle gravity. - tg_do_gravity_tick(obj); - - // Handle input. - tg_handle_move(obj, move); - - // Check for cleared lines - lines_cleared = tg_check_lines(obj); - - tg_adjust_score(obj, lines_cleared); - - // Return whether the game will continue (NOT whether it's over) - return !tg_game_over(obj); -} - -void tg_init(tetris_game *obj, int rows, int cols) -{ - // Initialization logic - obj->rows = rows; - obj->cols = cols; - obj->board = (char *)malloc(rows * cols); - memset(obj->board, TC_EMPTY, rows * cols); - obj->points = 0; - obj->level = 0; - obj->ticks_till_gravity = GRAVITY_LEVEL[obj->level]; - obj->lines_remaining = LINES_PER_LEVEL; - srand(time(NULL)); - tg_new_falling(obj); - tg_new_falling(obj); - obj->stored.typ = -1; - obj->stored.ori = 0; - obj->stored.loc.row = 0; - obj->next.loc.col = obj->cols/2 - 2; - printf("%d", obj->falling.loc.col); -} - -tetris_game *tg_create(int rows, int cols) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - tg_init(obj, rows, cols); - return obj; -} - -void tg_destroy(tetris_game *obj) -{ - // Cleanup logic - free(obj->board); -} - -void tg_delete(tetris_game *obj) { - tg_destroy(obj); - free(obj); -} - -/* - Load a game from a file. - */ -tetris_game *tg_load(FILE *f) -{ - tetris_game *obj = (tetris_game *)malloc(sizeof(tetris_game)); - if (fread(obj, sizeof(tetris_game), 1, f) != 1 ) - { - fprintf(stderr,"read game error\n"); - free(obj); - obj = 0; - } - else - { - obj->board = (char *)malloc(obj->rows * obj->cols); - if (fread(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - { - fprintf(stderr,"fread error\n"); - free(obj->board); - free(obj); - obj = 0; - } - } - return obj; -} - -/* - Save a game to a file. - */ -void tg_save(tetris_game *obj, FILE *f) -{ - if (fwrite(obj, sizeof(tetris_game), 1, f) != 1 ) - fprintf(stderr,"error writing tetrisgame\n"); - else if (fwrite(obj->board, sizeof(char), obj->rows * obj->cols, f) != obj->rows * obj->cols ) - fprintf(stderr,"error writing board\n"); -} - -/* - Print a game board to a file. Really just for early debugging. - */ -void tg_print(tetris_game *obj, FILE *f) { - int i, j; - for (i = 0; i < obj->rows; i++) { - for (j = 0; j < obj->cols; j++) { - if (TC_IS_EMPTY(tg_get(obj, i, j))) { - fputs(TC_EMPTY_STR, f); - } else { - fputs(TC_BLOCK_STR, f); - } - } - fputc('\n', f); - } -} - -/* - 2 columns per cell makes the game much nicer. - */ -#define COLS_PER_CELL 2 -/* - Macro to print a cell of a specific type to a window. - */ -#define ADD_BLOCK(w,x) waddch((w),' '|A_REVERSE|COLOR_PAIR(x)); \ -waddch((w),' '|A_REVERSE|COLOR_PAIR(x)) -#define ADD_EMPTY(w) waddch((w), ' '); waddch((w), ' ') - -/* - Print the tetris board onto the ncurses window. - */ -void display_board(WINDOW *w, tetris_game *obj) -{ - int i, j; - box(w, 0, 0); - for (i = 0; i < obj->rows; i++) { - wmove(w, 1 + i, 1); - for (j = 0; j < obj->cols; j++) { - if (TC_IS_FILLED(tg_get(obj, i, j))) { - ADD_BLOCK(w,tg_get(obj, i, j)); - } else { - ADD_EMPTY(w); - } - } - } - wnoutrefresh(w); -} - -/* - Display a tetris piece in a dedicated window. - */ -void display_piece(WINDOW *w, tetris_block block) -{ - int b; - tetris_location c; - wclear(w); - box(w, 0, 0); - if (block.typ == -1) { - wnoutrefresh(w); - return; - } - for (b = 0; b < TETRIS; b++) { - c = TETROMINOS[block.typ][block.ori][b]; - wmove(w, c.row + 1, c.col * COLS_PER_CELL + 1); - ADD_BLOCK(w, TYPE_TO_CELL(block.typ)); - } - wnoutrefresh(w); -} - -/* - Display score information in a dedicated window. - */ -void display_score(WINDOW *w, tetris_game *tg) -{ - wclear(w); - box(w, 0, 0); - wprintw(w, "Score\n%d\n", tg->points); - wprintw(w, "Level\n%d\n", tg->level); - wprintw(w, "Lines\n%d\n", tg->lines_remaining); - wnoutrefresh(w); -} - -/* - Boss mode! Make it look like you're doing work. - */ -void boss_mode(void) -{ - clear(); - //Mix_PauseMusic(); - printw("user@workstation-312:~/Documents/presentation $ ls -l\n" - "total 528\n" - "drwxr-xr-x 2 user users 4096 Jun 9 17:05 .\n" - "drwxr-xr-x 4 user users 4096 Jun 10 09:52 ..\n" - "-rw-r--r-- 1 user users 88583 Jun 9 14:13 figure1.png\n" - "-rw-r--r-- 1 user users 65357 Jun 9 15:40 figure2.png\n" - "-rw-r--r-- 1 user users 4469 Jun 9 16:17 presentation.aux\n" - "-rw-r--r-- 1 user users 42858 Jun 9 16:17 presentation.log\n" - "-rw-r--r-- 1 user users 2516 Jun 9 16:17 presentation.nav\n" - "-rw-r--r-- 1 user users 183 Jun 9 16:17 presentation.out\n" - "-rw-r--r-- 1 user users 349607 Jun 9 16:17 presentation.pdf\n" - "-rw-r--r-- 1 user users 0 Jun 9 16:17 presentation.snm\n" - "-rw-r--r-- 1 user users 9284 Jun 9 17:05 presentation.tex\n" - "-rw-r--r-- 1 user users 229 Jun 9 16:17 presentation.toc\n" - "\n" - "user@workstation-312:~/Documents/presentation $ "); - echo(); - timeout(-1); - while (getch() != KEY_F(1)); - timeout(0); - noecho(); - clear(); - //Mix_ResumeMusic(); -} - -/* - Save and exit the game. - */ -void save(tetris_game *game, WINDOW *w) -{ - FILE *f; - - wclear(w); - box(w, 0, 0); // return the border - wmove(w, 1, 1); - wprintw(w, "Save and exit? [Y/n] "); - wrefresh(w); - timeout(-1); - if (getch() == 'n') { - timeout(0); - return; - } - f = fopen("tetris.save", "w"); - tg_save(game, f); - fclose(f); - tg_delete(game); - endwin(); - printf("Game saved to \"tetris.save\".\n"); - printf("Resume by passing the filename as an argument to this program.\n"); - exit(EXIT_SUCCESS); -} - -/* - Do the NCURSES initialization steps for color blocks. - */ -void init_colors(void) -{ - start_color(); - //init_color(COLOR_ORANGE, 1000, 647, 0); - init_pair(TC_CELLI, COLOR_CYAN, COLOR_BLACK); - init_pair(TC_CELLJ, COLOR_BLUE, COLOR_BLACK); - init_pair(TC_CELLL, COLOR_WHITE, COLOR_BLACK); - init_pair(TC_CELLO, COLOR_YELLOW, COLOR_BLACK); - init_pair(TC_CELLS, COLOR_GREEN, COLOR_BLACK); - init_pair(TC_CELLT, COLOR_MAGENTA, COLOR_BLACK); - init_pair(TC_CELLZ, COLOR_RED, COLOR_BLACK); -} - -/* - Main tetris game! - */ -#ifdef STANDALONE - -int main(int argc, char **argv) -{ - tetris_game *tg; - tetris_move move = TM_NONE; - bool running = true; - WINDOW *board, *next, *hold, *score; - //Mix_Music *music; - - // Load file if given a filename. - if (argc >= 2) { - FILE *f = fopen(argv[1], "r"); - if (f == NULL) { - perror("tetris"); - exit(EXIT_FAILURE); - } - tg = tg_load(f); - fclose(f); - } else { - // Otherwise create new game. - tg = tg_create(22, 10); - } - - /* Initialize music. - if (SDL_Init(SDL_INIT_AUDIO) < 0) { - fprintf(stderr, "unable to initialize SDL\n"); - exit(EXIT_FAILURE); - } - if (Mix_Init(MIX_INIT_MP3) != MIX_INIT_MP3) { - fprintf(stderr, "unable to initialize SDL_mixer\n"); - exit(EXIT_FAILURE); - } - if (Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) != 0) { - fprintf(stderr, "unable to initialize audio\n"); - exit(EXIT_FAILURE); - } - Mix_AllocateChannels(1); // only need background music - music = Mix_LoadMUS("tetris.mp3"); - if (music) { - Mix_PlayMusic(music, -1); - }*/ - - // NCURSES initialization: - initscr(); // initialize curses - cbreak(); // pass key presses to program, but not signals - noecho(); // don't echo key presses to screen - keypad(stdscr, TRUE); // allow arrow keys - timeout(0); // no blocking on getch() - curs_set(0); // set the cursor to invisible - init_colors(); // setup tetris colors - - // Create windows for each section of the interface. - board = newwin(tg->rows + 2, 2 * tg->cols + 2, 0, 0); - next = newwin(6, 10, 0, 2 * (tg->cols + 1) + 1); - hold = newwin(6, 10, 7, 2 * (tg->cols + 1) + 1); - score = newwin(6, 10, 14, 2 * (tg->cols + 1 ) + 1); - int32_t counter = 0; - // Game loop - while (running) { - running = tg_tick(tg, move); - display_board(board, tg); - display_piece(next, tg->next); - display_piece(hold, tg->stored); - display_score(score, tg); - if ( (counter++ % 5) == 0 ) - doupdate(); - sleep_milli(10); - - switch (getch()) { - case KEY_LEFT: - move = TM_LEFT; - break; - case KEY_RIGHT: - move = TM_RIGHT; - break; - case KEY_UP: - move = TM_CLOCK; - break; - case KEY_DOWN: - move = TM_DROP; - break; - case 'q': - running = false; - move = TM_NONE; - break; - case 'p': - wclear(board); - box(board, 0, 0); - wmove(board, tg->rows/2, (tg->cols*COLS_PER_CELL-6)/2); - wprintw(board, "PAUSED"); - wrefresh(board); - timeout(-1); - getch(); - timeout(0); - move = TM_NONE; - break; - case 'b': - boss_mode(); - move = TM_NONE; - break; - case 's': - save(tg, board); - move = TM_NONE; - break; - case ' ': - move = TM_HOLD; - break; - default: - move = TM_NONE; - } - } - - // Deinitialize NCurses - wclear(stdscr); - endwin(); - - /* Deinitialize Sound - Mix_HaltMusic(); - Mix_FreeMusic(music); - Mix_CloseAudio(); - Mix_Quit();*/ - - // Output ending message. - printf("Game over!\n"); - printf("You finished with %d points on level %d.\n", tg->points, tg->level); - - // Deinitialize Tetris - tg_delete(tg); - return 0; -} -#else - -/****************************************************************************** - * 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" -#include "CCinclude.h" - -#define TETRIS_REGISTRATION 5 -#define TETRIS_REGISTRATIONSIZE (100 * 10000) -#define TETRIS_MAXPLAYERS 64 // need to send unused fees back to globalCC address to prevent leeching -#define TETRIS_MAXKEYSTROKESGAP 60 -#define TETRIS_MAXITERATIONS 777 - - -std::string Tetris_pname = ""; - -CScript tetris_newgameopret(int64_t buyin,int32_t maxplayers) -{ - CScript opret; uint8_t evalcode = EVAL_TETRIS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'G' << buyin << maxplayers); - return(opret); -} - -CScript tetris_registeropret(uint256 gametxid,uint256 playertxid) -{ - CScript opret; uint8_t evalcode = EVAL_TETRIS; - //fprintf(stderr,"opret.(%s %s).R\n",gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'R' << gametxid << playertxid); - return(opret); -} - -CScript tetris_keystrokesopret(uint256 gametxid,uint256 batontxid,CPubKey pk,std::vectorkeystrokes) -{ - CScript opret; uint8_t evalcode = EVAL_TETRIS; - opret << OP_RETURN << E_MARSHAL(ss << evalcode << 'K' << gametxid << batontxid << pk << keystrokes); - return(opret); -} - -CScript tetris_highlanderopret(uint8_t funcid,uint256 gametxid,int32_t regslot,CPubKey pk,std::vectorplayerdata,std::string pname) -{ - CScript opret; uint8_t evalcode = EVAL_TETRIS; std::string symbol(ASSETCHAINS_SYMBOL); - opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << gametxid << symbol << pname << regslot << pk << playerdata ); - return(opret); -} - -uint8_t tetris_highlanderopretdecode(uint256 &gametxid, uint256 &tokenid, int32_t ®slot, CPubKey &pk, std::vector &playerdata, std::string &symbol, std::string &pname,CScript scriptPubKey) -{ - std::string name, description; std::vector vorigPubkey; - std::vector> oprets, opretsDummy; - std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; - uint8_t e, f,*script; std::vector voutPubkeys; - tokenid = zeroid; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description, oprets)) == 'c' ) - { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - vopret = vopretNonfungible; - } - else if ( script[1] != 'H' && script[1] != 'Q' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, opretsDummy)) != 0 ) - { - //fprintf(stderr,"decode opret %c tokenid.%s\n",script[1],tokenid.GetHex().c_str()); - GetNonfungibleData(tokenid, vopretNonfungible); //load nonfungible data from the 'tokenbase' tx - vopret = vopretNonfungible; - } - if ( vopret.size() > 2 && E_UNMARSHAL(vopret, ss >> e; ss >> f; ss >> gametxid; ss >> symbol; ss >> pname; ss >> regslot; ss >> pk; ss >> playerdata) != 0 && e == EVAL_TETRIS && (f == 'H' || f == 'Q') ) - { - return(f); - } - fprintf(stderr,"SKIP obsolete: e.%d f.%c game.%s regslot.%d psize.%d\n",e,f,gametxid.GetHex().c_str(),regslot,(int32_t)playerdata.size()); - return(0); -} - -uint8_t tetris_keystrokesopretdecode(uint256 &gametxid,uint256 &batontxid,CPubKey &pk,std::vector &keystrokes,CScript scriptPubKey) -{ - std::vector vopret; uint8_t e,f; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> batontxid; ss >> pk; ss >> keystrokes) != 0 && e == EVAL_TETRIS && f == 'K' ) - { - return(f); - } - return(0); -} - -uint8_t tetris_registeropretdecode(uint256 &gametxid,uint256 &tokenid,uint256 &playertxid,CScript scriptPubKey) -{ - std::string name, description; std::vector vorigPubkey; - std::vector> oprets; - std::vector vopretNonfungible, vopret, vopretDummy,origpubkey; - uint8_t e, f,*script; std::vector voutPubkeys; - tokenid = zeroid; - GetOpReturnData(scriptPubKey, vopret); - script = (uint8_t *)vopret.data(); - if ( script[1] == 'c' && (f= DecodeTokenCreateOpRet(scriptPubKey,origpubkey,name,description,oprets)) == 'c' ) - { - GetOpretBlob(oprets, OPRETID_NONFUNGIBLEDATA, vopretNonfungible); - vopret = vopretNonfungible; - } - else if ( script[1] != 'R' && (f= DecodeTokenOpRet(scriptPubKey, e, tokenid, voutPubkeys, oprets)) != 0 ) - { - GetOpretBlob(oprets, OPRETID_TETRISGAMEDATA, vopretDummy); // blob from non-creation tx opret - vopret = vopretDummy; - } - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> gametxid; ss >> playertxid) != 0 && e == EVAL_TETRIS && f == 'R' ) - { - return(f); - } - //fprintf(stderr,"e.%d f.%c game.%s playertxid.%s\n",e,f,gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - return(0); -} - -uint8_t tetris_newgameopreturndecode(int64_t &buyin,int32_t &maxplayers,CScript scriptPubKey) -{ - std::vector vopret; uint8_t e,f; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> buyin; ss >> maxplayers) != 0 && e == EVAL_TETRIS && f == 'G' ) - { - return(f); - } - return(0); -} - -void tetris_univalue(UniValue &result,const char *method,int64_t maxplayers,int64_t buyin) -{ - if ( method != 0 ) - { - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method",method)); - } - if ( maxplayers > 0 ) - result.push_back(Pair("maxplayers",maxplayers)); - if ( buyin >= 0 ) - { - result.push_back(Pair("buyin",ValueFromAmount(buyin))); - if ( buyin == 0 ) - result.push_back(Pair("type","newbie")); - else result.push_back(Pair("type","buyin")); - } -} - -int32_t tetris_iamregistered(int32_t maxplayers,uint256 gametxid,CTransaction tx,char *mytetrisaddr) -{ - int32_t i,vout; uint256 spenttxid,hashBlock; CTransaction spenttx; char destaddr[64]; - for (i=0; i= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - { - Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); - if ( strcmp(mytetrisaddr,destaddr) == 0 ) - return(1); - //else fprintf(stderr,"myaddr.%s vs %s\n",mytetrisaddr,destaddr); - } //else fprintf(stderr,"cant find spenttxid.%s\n",spenttxid.GetHex().c_str()); - } //else fprintf(stderr,"vout %d is unspent\n",vout); - } - return(0); -} - -int32_t tetris_isvalidgame(struct CCcontract_info *cp,int32_t &gameheight,CTransaction &tx,int64_t &buyin,int32_t &maxplayers,uint256 txid,int32_t unspentv0) -{ - uint256 hashBlock; int32_t i,numvouts; char coinaddr[64]; CPubKey tetrispk; uint64_t txfee = 10000; - buyin = maxplayers = 0; - if ( (txid == zeroid || myGetTransaction(txid,tx,hashBlock) != 0) && (numvouts= tx.vout.size()) > 1 ) - { - if ( txid != zeroid ) - gameheight = komodo_blockheight(hashBlock); - else - { - txid = tx.GetHash(); - //fprintf(stderr,"set txid %s %llu\n",txid.GetHex().c_str(),(long long)CCgettxout(txid,0,1)); - } - if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) == txfee && (unspentv0 == 0 || CCgettxout(txid,0,1,0) == txfee) ) - { - if ( tetris_newgameopreturndecode(buyin,maxplayers,tx.vout[numvouts-1].scriptPubKey) == 'G' ) - { - if ( maxplayers < 1 || maxplayers > TETRIS_MAXPLAYERS || buyin < 0 ) - return(-6); - if ( numvouts > 2*maxplayers+1 ) - { - for (i=0; i playerdata,uint256 playertxid,uint256 tokenid,std::string symbol,std::string pname,uint256 gametxid) -{ - int32_t i,vout,spentvini,numvouts,n=0; uint256 txid,spenttxid,hashBlock; struct tetris_player P; char packitemstr[512],*datastr=0; UniValue obj(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx; - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - datastr = (char *)malloc(playerdata.size()*2+1); - for (i=0; i= 0 ) - txid = spenttxid; - else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - break; - } - txid = spenttxid; - vout = 0; - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) - { - for (i=0; i TETRIS_MAXITERATIONS ) - break; - } - obj.push_back(Pair("gametxid",gametxid.GetHex())); - if ( txid != playertxid ) - obj.push_back(Pair("batontxid",txid.GetHex())); - obj.push_back(Pair("playertxid",playertxid.GetHex())); - if ( tokenid != zeroid ) - obj.push_back(Pair("tokenid",tokenid.GetHex())); - else obj.push_back(Pair("tokenid",playertxid.GetHex())); - if ( datastr != 0 ) - { - obj.push_back(Pair("data",datastr)); - free(datastr); - } - obj.push_back(Pair("pack",a)); - obj.push_back(Pair("packsize",(int64_t)P.packsize)); - obj.push_back(Pair("hitpoints",(int64_t)P.hitpoints)); - obj.push_back(Pair("strength",(int64_t)(P.strength&0xffff))); - obj.push_back(Pair("maxstrength",(int64_t)(P.strength>>16))); - obj.push_back(Pair("level",(int64_t)P.level)); - obj.push_back(Pair("experience",(int64_t)P.experience)); - obj.push_back(Pair("dungeonlevel",(int64_t)P.dungeonlevel)); - obj.push_back(Pair("chain",symbol)); - obj.push_back(Pair("pname",pname)); - return(obj); -} - -int32_t tetris_iterateplayer(uint256 ®istertxid,uint256 firsttxid,int32_t firstvout,uint256 lasttxid) // retrace playertxid vins to reach highlander <- this verifies player is valid and tetris_playerdataspend makes sure it can only be used once -{ - uint256 spenttxid,txid = firsttxid; int32_t spentvini,n,vout = firstvout; - registertxid = zeroid; - if ( vout < 0 ) - return(-1); - n = 0; - while ( (spentvini= myIsutxo_spent(spenttxid,txid,vout)) == 0 ) - { - txid = spenttxid; - vout = spentvini; - if ( registertxid == zeroid ) - registertxid = txid; - if ( ++n >= TETRIS_MAXITERATIONS ) - { - fprintf(stderr,"tetris_iterateplayer n.%d, seems something is wrong\n",n); - return(-2); - } - } - if ( txid == lasttxid ) - return(0); - else - { - fprintf(stderr,"firsttxid.%s/v%d -> %s != last.%s\n",firsttxid.ToString().c_str(),firstvout,txid.ToString().c_str(),lasttxid.ToString().c_str()); - return(-1); - } -} - -/* - playertxid is whoever owns the nonfungible satoshi and it might have been bought and sold many times. - highlander is the game winning tx with the player data and is the only place where the unique player data exists - origplayergame is the gametxid that ends up being won by the highlander and they are linked directly as the highlander tx spends gametxid.vout0 - */ - -int32_t tetris_playerdata(struct CCcontract_info *cp,uint256 &origplayergame,uint256 &tokenid,CPubKey &pk,std::vector &playerdata,std::string &symbol,std::string &pname,uint256 playertxid) -{ - uint256 origplayertxid,hashBlock,gametxid,registertxid; CTransaction gametx,playertx,highlandertx; std::vector vopret; uint8_t *script,e,f; int32_t i,regslot,gameheight,numvouts,maxplayers; int64_t buyin; - if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 && (numvouts= playertx.vout.size()) > 0 ) - { - if ( (f= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,playertx.vout[numvouts-1].scriptPubKey)) == 'H' || f == 'Q' ) - { - origplayergame = gametxid; - if ( tokenid != zeroid ) - { - playertxid = tokenid; - if ( myGetTransaction(playertxid,playertx,hashBlock) == 0 || (numvouts= playertx.vout.size()) <= 0 ) - { - fprintf(stderr,"couldnt get tokenid.%s\n",playertxid.GetHex().c_str()); - return(-2); - } - } - if ( tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) - { - //fprintf(stderr,"playertxid.%s got vin.%s/v%d gametxid.%s iterate.%d\n",playertxid.ToString().c_str(),playertx.vin[1].prevout.hash.ToString().c_str(),(int32_t)playertx.vin[1].prevout.n-maxplayers,gametxid.ToString().c_str(),tetris_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid)); - if ( (tokenid != zeroid || playertx.vin[1].prevout.hash == gametxid) && tetris_iterateplayer(registertxid,gametxid,playertx.vin[1].prevout.n-maxplayers,playertxid) == 0 ) - { - // if registertxid has vin from pk, it can be used - return(0); - } else fprintf(stderr,"hash mismatch or illegal gametxid\n"); - } else fprintf(stderr,"invalid game %s\n",gametxid.GetHex().c_str()); - } //else fprintf(stderr,"invalid player funcid.%c\n",f); - } else fprintf(stderr,"couldnt get playertxid.%s\n",playertxid.GetHex().c_str()); - return(-1); -} - -int32_t tetris_playerdataspend(CMutableTransaction &mtx,uint256 playertxid,int32_t vout,uint256 origplayergame) -{ - int64_t txfee = 10000; CTransaction tx; uint256 hashBlock; - if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation - { - mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); - return(0); - } - else - { - vout = 0; - if ( myGetTransaction(playertxid,tx,hashBlock) != 0 && tx.vout[vout].nValue == 1 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 ) - { - if ( CCgettxout(playertxid,vout,1,0) == 1 ) // not sure if this is enough validation - { - mtx.vin.push_back(CTxIn(playertxid,vout,CScript())); - return(0); - } - } - return(-1); - } -} - -int32_t tetris_findbaton(struct CCcontract_info *cp,uint256 &playertxid,char **keystrokesp,int32_t &numkeys,int32_t ®slot,std::vector &playerdata,uint256 &batontxid,int32_t &batonvout,int64_t &batonvalue,int32_t &batonht,uint256 gametxid,CTransaction gametx,int32_t maxplayers,char *destaddr,int32_t &numplayers,std::string &symbol,std::string &pname) -{ - int32_t i,numvouts,spentvini,n,matches = 0; CPubKey pk; uint256 tid,active,spenttxid,tokenid,hashBlock,txid,origplayergame; CTransaction spenttx,matchtx,batontx; std::vector checkdata; CBlockIndex *pindex; char ccaddr[64],*keystrokes=0; - batonvalue = numkeys = numplayers = batonht = 0; - playertxid = batontxid = zeroid; - for (i=0; i= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - { - numplayers++; - Getscriptaddress(ccaddr,spenttx.vout[0].scriptPubKey); - if ( strcmp(destaddr,ccaddr) == 0 ) - { - matches++; - regslot = i; - matchtx = spenttx; - } //else fprintf(stderr,"%d+1 doesnt match %s vs %s\n",i,ccaddr,destaddr); - } //else fprintf(stderr,"%d+1 couldnt find spenttx.%s\n",i,spenttxid.GetHex().c_str()); - } //else fprintf(stderr,"%d+1 unspent\n",i); - } - if ( matches == 1 ) - { - numvouts = matchtx.vout.size(); - //fprintf(stderr,"matchtxid.%s matches.%d numvouts.%d\n",matchtx.GetHash().GetHex().c_str(),matches,numvouts); - if ( tetris_registeropretdecode(txid,tokenid,playertxid,matchtx.vout[numvouts-1].scriptPubKey) == 'R' )//&& txid == gametxid ) - { - //fprintf(stderr,"tokenid.%s txid.%s vs gametxid.%s player.%s\n",tokenid.GetHex().c_str(),txid.GetHex().c_str(),gametxid.GetHex().c_str(),playertxid.GetHex().c_str()); - if ( tokenid != zeroid ) - active = tokenid; - else active = playertxid; - if ( active == zeroid || tetris_playerdata(cp,origplayergame,tid,pk,playerdata,symbol,pname,active) == 0 ) - { - txid = matchtx.GetHash(); - //fprintf(stderr,"scan forward active.%s spenttxid.%s\n",active.GetHex().c_str(),txid.GetHex().c_str()); - n = 0; - while ( CCgettxout(txid,0,1,0) < 0 ) - { - spenttxid = zeroid; - spentvini = -1; - if ( (spentvini= myIsutxo_spent(spenttxid,txid,0)) >= 0 ) - txid = spenttxid; - else - { - if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,0) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - return(-2); - } - } - txid = spenttxid; - //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); - if ( spentvini != 0 ) // game is over? - { - return(0); - } - if ( keystrokesp != 0 && myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() >= 2 ) - { - uint256 g,b; CPubKey p; std::vector k; - if ( tetris_keystrokesopretdecode(g,b,p,k,spenttx.vout[spenttx.vout.size()-1].scriptPubKey) == 'K' ) - { - keystrokes = (char *)realloc(keystrokes,numkeys + (int32_t)k.size()); - for (i=0; i= TETRIS_MAXITERATIONS ) - { - fprintf(stderr,"tetris_findbaton n.%d, seems something is wrong\n",n); - return(-5); - } - } - //fprintf(stderr,"set baton %s\n",txid.GetHex().c_str()); - batontxid = txid; - batonvout = 0; // not vini - // how to detect timeout, bailedout, highlander - hashBlock = zeroid; - if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 0 ) - { - if ( hashBlock == zeroid ) - batonht = komodo_nextheight(); - else if ( (pindex= komodo_blockindex(hashBlock)) == 0 ) - return(-4); - else batonht = pindex->GetHeight(); - batonvalue = batontx.vout[0].nValue; - //printf("batonht.%d keystrokes[%d]\n",batonht,numkeys); - return(0); - } else fprintf(stderr,"couldnt find baton\n"); - } else fprintf(stderr,"error with playerdata\n"); - } else fprintf(stderr,"findbaton opret error\n"); - } - return(-1); -} - -int32_t tetris_playersalive(int32_t &openslots,int32_t &numplayers,uint256 gametxid,int32_t maxplayers,int32_t gameht,CTransaction gametx) -{ - int32_t i,n,vout,spentvini,registration_open = 0,alive = 0; CTransaction tx; uint256 txid,spenttxid,hashBlock; CBlockIndex *pindex; uint64_t txfee = 10000; - numplayers = openslots = 0; - if ( komodo_nextheight() <= gameht+TETRIS_MAXKEYSTROKESGAP ) - registration_open = 1; - for (i=0; i= 0 ) - txid = spenttxid; - else if ( myIsutxo_spentinmempool(spenttxid,spentvini,txid,vout) == 0 || spenttxid == zeroid ) - { - fprintf(stderr,"mempool tracking error %s/v0\n",txid.ToString().c_str()); - break; - } - txid = spenttxid; - vout = 0; - //fprintf(stderr,"n.%d next txid.%s/v%d\n",n,txid.GetHex().c_str(),spentvini); - if ( spentvini != 0 ) - break; - if ( n++ > TETRIS_MAXITERATIONS ) - break; - } - if ( txid != zeroid ) - { - if ( myGetTransaction(txid,tx,hashBlock) != 0 ) - { - if ( (pindex= komodo_blockindex(hashBlock)) != 0 ) - { - if ( pindex->GetHeight() <= gameht+TETRIS_MAXKEYSTROKESGAP ) - alive++; - } - } - } - } - } - else if ( registration_open != 0 ) - openslots++; - } - //fprintf(stderr,"numalive.%d openslots.%d\n",alive,openslots); - return(alive); -} - -uint64_t tetris_gamefields(UniValue &obj,int64_t maxplayers,int64_t buyin,uint256 gametxid,char *mytetrisaddr) -{ - CBlockIndex *pindex; int32_t ht,openslots,delay,numplayers; uint256 hashBlock; uint64_t seed=0; char cmd[512]; CTransaction tx; - if ( myGetTransaction(gametxid,tx,hashBlock) != 0 && (pindex= komodo_blockindex(hashBlock)) != 0 ) - { - ht = pindex->GetHeight(); - delay = TETRIS_REGISTRATION * (maxplayers > 1); - obj.push_back(Pair("height",ht)); - obj.push_back(Pair("start",ht+delay)); - if ( komodo_nextheight() > ht+delay ) - { - if ( (pindex= komodo_chainactive(ht+delay)) != 0 ) - { - hashBlock = pindex->GetBlockHash(); - obj.push_back(Pair("starthash",hashBlock.ToString())); - memcpy(&seed,&hashBlock,sizeof(seed)); - seed &= (1LL << 62) - 1; - obj.push_back(Pair("seed",(int64_t)seed)); - if ( tetris_iamregistered(maxplayers,gametxid,tx,mytetrisaddr) > 0 ) - sprintf(cmd,"cc/tetris %llu %s",(long long)seed,gametxid.ToString().c_str()); - else sprintf(cmd,"./komodo-cli -ac_name=%s cclib register %d \"[%%22%s%%22]\"",ASSETCHAINS_SYMBOL,EVAL_TETRIS,gametxid.ToString().c_str()); - obj.push_back(Pair("run",cmd)); - } - } - obj.push_back(Pair("alive",tetris_playersalive(openslots,numplayers,gametxid,maxplayers,ht,tx))); - obj.push_back(Pair("openslots",openslots)); - obj.push_back(Pair("numplayers",numplayers)); - } - obj.push_back(Pair("maxplayers",maxplayers)); - obj.push_back(Pair("buyin",ValueFromAmount(buyin))); - return(seed); -} - -void tetris_gameplayerinfo(struct CCcontract_info *cp,UniValue &obj,uint256 gametxid,CTransaction gametx,int32_t vout,int32_t maxplayers,char *mytetrisaddr) -{ - // identify if bailout or quit or timed out - uint256 batontxid,spenttxid,gtxid,ptxid,tokenid,hashBlock,playertxid; CTransaction spenttx,batontx; int32_t numplayers,regslot,numkeys,batonvout,batonht,retval; int64_t batonvalue; std::vector playerdata; char destaddr[64]; std::string symbol,pname; - destaddr[0] = 0; - if ( myIsutxo_spent(spenttxid,gametxid,vout) >= 0 ) - { - if ( myGetTransaction(spenttxid,spenttx,hashBlock) != 0 && spenttx.vout.size() > 0 ) - Getscriptaddress(destaddr,spenttx.vout[0].scriptPubKey); - } - obj.push_back(Pair("slot",(int64_t)vout-1)); - if ( (retval= tetris_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,destaddr,numplayers,symbol,pname)) == 0 ) - { - if ( CCgettxout(gametxid,maxplayers+vout,1,0) == 10000 ) - { - if ( myGetTransaction(batontxid,batontx,hashBlock) != 0 && batontx.vout.size() > 1 ) - { - if ( tetris_registeropretdecode(gtxid,tokenid,ptxid,batontx.vout[batontx.vout.size()-1].scriptPubKey) == 'R' && ptxid == playertxid && gtxid == gametxid ) - obj.push_back(Pair("status","registered")); - else obj.push_back(Pair("status","alive")); - } else obj.push_back(Pair("status","error")); - } else obj.push_back(Pair("status","finished")); - obj.push_back(Pair("baton",batontxid.ToString())); - obj.push_back(Pair("tokenid",tokenid.ToString())); - obj.push_back(Pair("batonaddr",destaddr)); - obj.push_back(Pair("ismine",strcmp(mytetrisaddr,destaddr)==0)); - obj.push_back(Pair("batonvout",(int64_t)batonvout)); - obj.push_back(Pair("batonvalue",ValueFromAmount(batonvalue))); - obj.push_back(Pair("batonht",(int64_t)batonht)); - if ( playerdata.size() > 0 ) - obj.push_back(Pair("player",tetris_playerobj(playerdata,playertxid,tokenid,symbol,pname,gametxid))); - } else fprintf(stderr,"findbaton err.%d\n",retval); -} - -int64_t tetris_registrationbaton(CMutableTransaction &mtx,uint256 gametxid,CTransaction gametx,int32_t maxplayers) -{ - int32_t vout,j,r; int64_t nValue; - if ( gametx.vout.size() > maxplayers+1 ) - { - r = rand() % maxplayers; - for (j=0; j 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); -} - -UniValue tetris_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey tetrispk,mypk; char *jsonstr; uint64_t inputsum,change,required,buyin=0; int32_t i,n,maxplayers = 1; - if ( txfee == 0 ) - txfee = 10000; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - maxplayers = juint(jitem(params,0),0); - if ( n > 1 ) - buyin = jdouble(jitem(params,1),0) * COIN + 0.0000000049; - } - } - if ( maxplayers < 1 || maxplayers > TETRIS_MAXPLAYERS ) - return(cclib_error(result,"illegal maxplayers")); - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - tetris_univalue(result,"newgame",maxplayers,buyin); - required = (3*txfee + maxplayers*(TETRIS_REGISTRATIONSIZE+txfee)); - if ( (inputsum= AddCClibInputs(cp,mtx,tetrispk,required,16,cp->unspendableCCaddr)) >= required ) - { - mtx.vout.push_back(MakeCC1vout(cp->evalcode,txfee,tetrispk)); // for highlander TCBOO creation - for (i=0; ievalcode,TETRIS_REGISTRATIONSIZE,tetrispk,tetrispk)); - for (i=0; ievalcode,txfee,tetrispk,tetrispk)); - if ( (change= inputsum - required) >= txfee ) - mtx.vout.push_back(MakeCC1vout(cp->evalcode,change,tetrispk)); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,tetris_newgameopret(buyin,maxplayers)); - return(tetris_rawtxresult(result,rawtx,1)); - } - else return(cclib_error(result,"illegal maxplayers")); - return(result); -} - -UniValue tetris_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); std::vector playerdata; uint256 playertxid,tokenid,origplayergame;int32_t n; CPubKey pk; bits256 t; std::string symbol,pname; - result.push_back(Pair("result","success")); - tetris_univalue(result,"playerinfo",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - playertxid = juint256(jitem(params,0)); - if ( tetris_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) - return(cclib_error(result,"invalid playerdata")); - result.push_back(Pair("player",tetris_playerobj(playerdata,playertxid,tokenid,symbol,pname,origplayergame))); - } else return(cclib_error(result,"no playertxid")); - return(result); - } else return(cclib_error(result,"couldnt reparse params")); -} - -UniValue tetris_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - // vin0 -> TETRIS_REGISTRATIONSIZE 1of2 registration baton from creategame - // vin1 -> optional nonfungible character vout @ - // vin2 -> original creation TCBOO playerdata used - // vin3+ -> buyin - // vout0 -> keystrokes/completion baton - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); char destaddr[64],coinaddr[64]; uint256 tokenid,gametxid,origplayergame,playertxid,hashBlock; int32_t err,maxplayers,gameheight,n,numvouts,vout=1; int64_t inputsum,buyin,CCchange=0; CPubKey pk,mypk,tetrispk,burnpk; CTransaction tx,playertx; std::vector playerdata; std::string rawtx,symbol,pname; bits256 t; - - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - burnpk = pubkey2pk(ParseHex(CC_BURNPUBKEY)); - tetrispk = GetUnspendable(cp,0); - tetris_univalue(result,"register",-1,-1); - playertxid = tokenid = zeroid; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - if ( (err= tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1)) == 0 ) - { - if ( n > 1 ) - { - playertxid = juint256(jitem(params,1)); - if ( tetris_playerdata(cp,origplayergame,tokenid,pk,playerdata,symbol,pname,playertxid) < 0 ) - return(cclib_error(result,"couldnt extract valid playerdata")); - if ( tokenid != zeroid ) // if it is tokentransfer this will be 0 - vout = 1; - } - if ( komodo_nextheight() > gameheight + TETRIS_MAXKEYSTROKESGAP ) - return(cclib_error(result,"didnt register in time, TETRIS_MAXKEYSTROKESGAP")); - tetris_univalue(result,0,maxplayers,buyin); - GetCCaddress1of2(cp,coinaddr,tetrispk,mypk); - if ( tetris_iamregistered(maxplayers,gametxid,tx,coinaddr) > 0 ) - return(cclib_error(result,"already registered")); - if ( (inputsum= tetris_registrationbaton(mtx,gametxid,tx,maxplayers)) != TETRIS_REGISTRATIONSIZE ) - return(cclib_error(result,"couldnt find available registration baton")); - else if ( playertxid != zeroid && tetris_playerdataspend(mtx,playertxid,vout,origplayergame) < 0 ) - return(cclib_error(result,"couldnt find playerdata to spend")); - else if ( buyin > 0 && AddNormalinputs(mtx,mypk,buyin,64) < buyin ) - return(cclib_error(result,"couldnt find enough normal funds for buyin")); - if ( tokenid != zeroid ) - { - mtx.vin.push_back(CTxIn(tokenid,0)); // spending cc marker as token is burned - char unspendableTokenAddr[64]; uint8_t tokenpriv[32]; struct CCcontract_info *cpTokens, tokensC; - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - CPubKey unspPk = GetUnspendable(cpTokens, tokenpriv); - GetCCaddress(cpTokens, unspendableTokenAddr, unspPk); - CCaddr2set(cp, EVAL_TOKENS, unspPk, tokenpriv, unspendableTokenAddr); - } - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,buyin + inputsum - txfee,tetrispk,mypk)); - GetCCaddress1of2(cp,destaddr,tetrispk,tetrispk); - CCaddr1of2set(cp,tetrispk,tetrispk,cp->CCpriv,destaddr); - mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode, 1, burnpk)); - - uint8_t e, funcid; uint256 tid; std::vector voutPubkeys, voutPubkeysEmpty; int32_t didtx = 0; - CScript opretRegister = tetris_registeropret(gametxid, playertxid); - if ( playertxid != zeroid ) - { - voutPubkeysEmpty.push_back(burnpk); - if ( myGetTransaction(playertxid,playertx,hashBlock) != 0 ) - { - std::vector> oprets; - if ( (funcid= DecodeTokenOpRet(playertx.vout.back().scriptPubKey, e, tid, voutPubkeys, oprets)) != 0) - { // if token in the opret - didtx = 1; - if ( funcid == 'c' ) - tid = tokenid == zeroid ? playertxid : tokenid; - vscript_t vopretRegister; - GetOpReturnData(opretRegister, vopretRegister); - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, - EncodeTokenOpRet(tid, voutPubkeysEmpty /*=never spent*/, std::make_pair(OPRETID_TETRISGAMEDATA, vopretRegister))); - } - } - } - if ( didtx == 0 ) - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, opretRegister); - - return(tetris_rawtxresult(result,rawtx,1)); - } else return(cclib_error(result,"invalid gametxid")); - } else return(cclib_error(result,"no gametxid")); - } else return(cclib_error(result,"couldnt reparse params")); -} - -UniValue tetris_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - // vin0 -> baton from registration or previous keystrokes - // vout0 -> new baton - // opret -> user input chars - // being killed should auto broadcast (possible to be suppressed?) - // respawn to be prevented by including timestamps - int32_t nextheight = komodo_nextheight(); - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),nextheight); - UniValue result(UniValue::VOBJ); CPubKey tetrispk,mypk; uint256 gametxid,playertxid,batontxid; int64_t batonvalue,buyin; std::vector keystrokes,playerdata; int32_t numplayers,regslot,numkeys,batonht,batonvout,n,elapsed,gameheight,maxplayers; CTransaction tx; CTxOut txout; char *keystrokestr,destaddr[64]; std::string rawtx,symbol,pname; bits256 t; uint8_t mypriv[32]; - if ( txfee == 0 ) - txfee = 10000; - tetris_univalue(result,"keystrokes",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) == 2 && (keystrokestr= jstr(jitem(params,1),0)) != 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - result.push_back(Pair("keystrokes",keystrokestr)); - keystrokes = ParseHex(keystrokestr); - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,destaddr,tetrispk,mypk); - if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,gametxid,1) == 0 ) - { - if ( tetris_findbaton(cp,playertxid,0,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,tx,maxplayers,destaddr,numplayers,symbol,pname) == 0 ) - { - result.push_back(Pair("batontxid",batontxid.GetHex())); - result.push_back(Pair("playertxid",playertxid.GetHex())); - if ( maxplayers == 1 || nextheight <= batonht+TETRIS_MAXKEYSTROKESGAP ) - { - mtx.vin.push_back(CTxIn(batontxid,batonvout,CScript())); //this validates user if pk - mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,batonvalue-txfee,tetrispk,mypk)); - Myprivkey(mypriv); - CCaddr1of2set(cp,tetrispk,mypk,mypriv,destaddr); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,tetris_keystrokesopret(gametxid,batontxid,mypk,keystrokes)); - //fprintf(stderr,"KEYSTROKES.(%s)\n",rawtx.c_str()); - return(tetris_rawtxresult(result,rawtx,1)); - } else return(cclib_error(result,"keystrokes tx was too late")); - } else return(cclib_error(result,"couldnt find batontxid")); - } else return(cclib_error(result,"invalid gametxid")); - } else return(cclib_error(result,"couldnt reparse params")); -} - -char *tetris_extractgame(int32_t makefiles,char *str,int32_t *numkeysp,std::vector &newdata,uint64_t &seed,uint256 &playertxid,struct CCcontract_info *cp,uint256 gametxid,char *tetrisaddr) -{ - CPubKey tetrispk; int32_t i,num,retval,maxplayers,gameheight,batonht,batonvout,numplayers,regslot,numkeys,err; std::string symbol,pname; CTransaction gametx; int64_t buyin,batonvalue; char fname[64],*keystrokes = 0; std::vector playerdata; uint256 batontxid; FILE *fp; uint8_t newplayer[10000]; struct tetris_player P,endP; - tetrispk = GetUnspendable(cp,0); - *numkeysp = 0; - seed = 0; - num = numkeys = 0; - playertxid = zeroid; - str[0] = 0; - if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0)) == 0 ) - { - if ( (retval= tetris_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,tetrisaddr,numplayers,symbol,pname)) == 0 ) - { - UniValue obj; - seed = tetris_gamefields(obj,maxplayers,buyin,gametxid,tetrisaddr); - //fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d playertxid.%s\n",pname.size()!=0?pname.c_str():Tetris_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size(),playertxid.GetHex().c_str()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i no playerdata\n"); - newdata.resize(0); - *numkeysp = numkeys; - return(keystrokes); - /* P.gold = (P.gold * 8) / 10; - if ( keystrokes != 0 ) - { - free(keystrokes); - keystrokes = 0; - *numkeysp = 0; - return(keystrokes); - }*/ - } - else - { - sprintf(str,"$$$gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d",endP.gold,endP.hitpoints,endP.strength&0xffff,endP.strength>>16,endP.level,endP.experience,endP.dungeonlevel); - //fprintf(stderr,"%s\n",str); - *numkeysp = numkeys; - return(keystrokes); - } - } else num = 0; - } - else - { - fprintf(stderr,"extractgame: couldnt find baton keystrokes.%p retval.%d\n",keystrokes,retval); - if ( keystrokes != 0 ) - free(keystrokes), keystrokes = 0; - } - } else fprintf(stderr,"extractgame: invalid game\n"); - //fprintf(stderr,"extract %s\n",gametxid.GetHex().c_str()); - return(0); -} - -UniValue tetris_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); CPubKey pk,tetrispk; int32_t i,n,numkeys,flag = 0; uint64_t seed; char str[512],tetrisaddr[64],*pubstr,*hexstr,*keystrokes = 0; std::vector newdata; uint256 gametxid,playertxid; FILE *fp; uint8_t pub33[33]; - pk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method","extract")); - tetrisaddr[0] = 0; - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - if ( n == 2 ) - { - if ( (pubstr= jstr(jitem(params,1),0)) != 0 ) - { - if (strlen(pubstr) == 66 ) - { - decode_hex(pub33,33,pubstr); - pk = buf2pk(pub33); - } - else if ( strlen(pubstr) < 36 ) - strcpy(tetrisaddr,pubstr); - } - //fprintf(stderr,"gametxid.%s %s\n",gametxid.GetHex().c_str(),pubstr); - } - if ( tetrisaddr[0] == 0 ) - GetCCaddress1of2(cp,tetrisaddr,tetrispk,pk); - result.push_back(Pair("tetrisaddr",tetrisaddr)); - str[0] = 0; - if ( (keystrokes= tetris_extractgame(1,str,&numkeys,newdata,seed,playertxid,cp,gametxid,tetrisaddr)) != 0 ) - { - result.push_back(Pair("status","success")); - flag = 1; - hexstr = (char *)malloc(numkeys*2 + 1); - for (i=0; i playerdata,uint256 gametxid,CPubKey pk) -{ - static uint32_t good,bad; static uint256 prevgame; - char str[512],*keystrokes,tetrisaddr[64],str2[67],fname[64]; int32_t i,dungeonlevel,numkeys; std::vector newdata; uint64_t seed,mult = 10; CPubKey tetrispk; struct tetris_player P; - *cashoutp = 0; - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,tetrisaddr,tetrispk,pk); - //fprintf(stderr,"call extractgame\n"); - if ( (keystrokes= tetris_extractgame(0,str,&numkeys,newdata,seed,playertxid,cp,gametxid,tetrisaddr)) != 0 ) - { - //fprintf(stderr,"numkeys.%d tetris_extractgame %s\n",numkeys,gametxid.GetHex().c_str()); - free(keystrokes); - sprintf(fname,"tetris.%llu.pack",(long long)seed); - remove(fname); - - //fprintf(stderr,"extracted.(%s)\n",str); - for (i=0; i no playerdata, good.%d bad.%d\n",good,bad); - } - *cashoutp = 0; - return(0); - } - } - if ( gametxid != prevgame ) - { - prevgame = gametxid; - bad++; - fprintf(stderr,"%s playerdata: gold.%d hp.%d strength.%d/%d level.%d exp.%d dl.%d\n",gametxid.GetHex().c_str(),P.gold,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel); - fprintf(stderr,"newdata[%d] != playerdata[%d], numkeys.%d %s pub.%s playertxid.%s good.%d bad.%d\n",(int32_t)newdata.size(),(int32_t)playerdata.size(),numkeys,tetrisaddr,pubkey33_str(str2,(uint8_t *)&pk),playertxid.GetHex().c_str(),good,bad); - } - } - sprintf(fname,"tetris.%llu.pack",(long long)seed); - remove(fname); - //fprintf(stderr,"no keys tetris_extractgame %s\n",gametxid.GetHex().c_str()); - return(-1); -} - -UniValue tetris_finishgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params,char *method) -{ - //vin0 -> highlander vout from creategame TCBOO - //vin1 -> keystrokes baton of completed game, must be last to quit or first to win, only spent registration batons matter. If more than 60 blocks since last keystrokes, it is forfeit - //vins2+ -> rest of unspent registration utxo so all newgame vouts are spent - //vout0 -> nonfungible character with pack @ - //vout1 -> 1% ingame gold and all the buyins - - // detect if last to bailout - // vin0 -> kestrokes baton of completed game with Q - // vout0 -> playerdata marker - // vout0 -> 1% ingame gold - // get any playerdata, get all keystrokes, replay game and compare final state - CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); - UniValue result(UniValue::VOBJ); std::string rawtx,symbol,pname; CTransaction gametx; uint64_t seed,mult; int64_t buyin,batonvalue,inputsum,cashout,CCchange=0; int32_t i,err,gameheight,tmp,numplayers,regslot,n,num,dungeonlevel,numkeys,maxplayers,batonht,batonvout; char mytetrisaddr[64],*keystrokes = 0; std::vector playerdata,newdata,nodata; uint256 batontxid,playertxid,gametxid; CPubKey mypk,tetrispk; uint8_t player[10000],mypriv[32],funcid; - struct CCcontract_info *cpTokens, tokensC; - - if ( txfee == 0 ) - txfee = 10000; - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,mytetrisaddr,tetrispk,mypk); - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method",method)); - result.push_back(Pair("mytetrisaddr",mytetrisaddr)); - if ( strcmp(method,"bailout") == 0 ) - { - funcid = 'Q'; - mult = 10; //100000; - } - else - { - funcid = 'H'; - mult = 20; //200000; - } - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - gametxid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",gametxid.GetHex())); - if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,1)) == 0 ) - { - if ( tetris_findbaton(cp,playertxid,&keystrokes,numkeys,regslot,playerdata,batontxid,batonvout,batonvalue,batonht,gametxid,gametx,maxplayers,mytetrisaddr,numplayers,symbol,pname) == 0 ) - { - UniValue obj; struct tetris_player P; - seed = tetris_gamefields(obj,maxplayers,buyin,gametxid,mytetrisaddr); - fprintf(stderr,"(%s) found baton %s numkeys.%d seed.%llu playerdata.%d\n",pname.size()!=0?pname.c_str():Tetris_pname.c_str(),batontxid.ToString().c_str(),numkeys,(long long)seed,(int32_t)playerdata.size()); - memset(&P,0,sizeof(P)); - if ( playerdata.size() > 0 ) - { - for (i=0; i 0 ) - { - newdata.resize(num); - for (i=0; i no playerdata\n"); - newdata.resize(0); - //P.gold = (P.gold * 8) / 10; - } - else - { - cpTokens = CCinit(&tokensC, EVAL_TOKENS); - mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, txfee, GetUnspendable(cpTokens,NULL))); // marker to token cc addr, burnable and validated - mtx.vout.push_back(MakeTokensCC1vout(cp->evalcode,1,mypk)); - if ( P.amulet != 0 ) - mult *= 5; - dungeonlevel = P.dungeonlevel; - if ( P.amulet != 0 && dungeonlevel < 21 ) - dungeonlevel = 21; - cashout = (uint64_t)P.gold * P.gold * mult * dungeonlevel; - fprintf(stderr,"\nextracted $$$gold.%d -> %.8f TETRIS hp.%d strength.%d/%d level.%d exp.%d dl.%d n.%d amulet.%d\n",P.gold,(double)cashout/COIN,P.hitpoints,P.strength&0xffff,P.strength>>16,P.level,P.experience,P.dungeonlevel,n,P.amulet); - if ( funcid == 'H' && maxplayers > 1 ) - { - if ( P.amulet == 0 ) - { - if ( numplayers != maxplayers ) - return(cclib_error(result,"numplayers != maxplayers")); - else if ( tetris_playersalive(tmp,tmp,gametxid,maxplayers,gameheight,gametx) > 1 ) - return(cclib_error(result,"highlander must be a winner or last one standing")); - } - cashout += numplayers * buyin; - } - if ( cashout >= txfee ) - { - if ( (inputsum= AddCClibInputs(cp,mtx,tetrispk,cashout,16,cp->unspendableCCaddr)) > (uint64_t)P.gold*mult ) - CCchange = (inputsum - cashout); - mtx.vout.push_back(CTxOut(cashout,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); - } - } - } - mtx.vout.push_back(MakeCC1vout(cp->evalcode,CCchange + (batonvalue-3*txfee),tetrispk)); - Myprivkey(mypriv); - CCaddr1of2set(cp,tetrispk,mypk,mypriv,mytetrisaddr); - CScript opret; - if ( pname.size() == 0 ) - pname = Tetris_pname; - if ( newdata.size() == 0 ) - { - opret = tetris_highlanderopret(funcid, gametxid, regslot, mypk, nodata,pname); - rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,opret); - //fprintf(stderr,"nodata finalizetx.(%s)\n",rawtx.c_str()); - } - else - { - opret = tetris_highlanderopret(funcid, gametxid, regslot, mypk, newdata,pname); - char seedstr[32]; - sprintf(seedstr,"%llu",(long long)seed); - std::vector vopretNonfungible; - GetOpReturnData(opret, vopretNonfungible); - rawtx = FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeTokenCreateOpRet('c', Mypubkey(), std::string(seedstr), gametxid.GetHex(), vopretNonfungible)); - } - return(tetris_rawtxresult(result,rawtx,1)); - } - result.push_back(Pair("result","success")); - } else fprintf(stderr,"illegal game err.%d\n",err); - } else fprintf(stderr,"parameters only n.%d\n",n); - } - return(result); -} - -UniValue tetris_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - return(tetris_finishgame(txfee,cp,params,"bailout")); -} - -UniValue tetris_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - return(tetris_finishgame(txfee,cp,params,"highlander")); -} - -UniValue tetris_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i,n,gameheight,maxplayers,numvouts; uint256 txid; CTransaction tx; int64_t buyin; uint64_t seed; bits256 t; char mytetrisaddr[64],str[64]; CPubKey mypk,tetrispk; - result.push_back(Pair("name","tetris")); - result.push_back(Pair("method","gameinfo")); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - txid = juint256(jitem(params,0)); - result.push_back(Pair("gametxid",txid.GetHex())); - if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,0) == 0 ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("gameheight",(int64_t)gameheight)); - mypk = pubkey2pk(Mypubkey()); - tetrispk = GetUnspendable(cp,0); - GetCCaddress1of2(cp,mytetrisaddr,tetrispk,mypk); - //fprintf(stderr,"mytetrisaddr.%s\n",mytetrisaddr); - seed = tetris_gamefields(result,maxplayers,buyin,txid,mytetrisaddr); - result.push_back(Pair("seed",(int64_t)seed)); - for (i=0; i > unspentOutputs; - tetrispk = GetUnspendable(cp,0); - GetCCaddress(cp,coinaddr,tetrispk); - SetCCunspents(unspentOutputs,coinaddr); - nextheight = komodo_nextheight(); - 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 ) // reject any that are not highlander markers - continue; - if ( tetris_isvalidgame(cp,gameheight,tx,buyin,maxplayers,txid,1) == 0 && nextheight <= gameheight+TETRIS_MAXKEYSTROKESGAP ) - { - tetris_playersalive(openslots,numplayers,txid,maxplayers,gameheight,tx); - if ( openslots > 0 ) - a.push_back(txid.GetHex()); - } - } - result.push_back(Pair("result","success")); - tetris_univalue(result,"pending",-1,-1); - result.push_back(Pair("pending",a)); - result.push_back(Pair("numpending",(int64_t)a.size())); - return(result); -} - -UniValue tetris_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR); int64_t buyin; uint256 tokenid,gametxid,txid,hashBlock; CTransaction playertx,tx; int32_t maxplayers,vout,numvouts; std::vector playerdata; CPubKey tetrispk,mypk,pk; std::string symbol,pname; char coinaddr[64]; - std::vector > unspentOutputs; - tetrispk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - GetTokensCCaddress(cp,coinaddr,mypk); - SetCCunspents(unspentOutputs,coinaddr); - tetris_univalue(result,"players",-1,-1); - 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 != 1 || vout > 1 ) - continue; - if ( tetris_playerdata(cp,gametxid,tokenid,pk,playerdata,symbol,pname,txid) == 0 )//&& pk == mypk ) - { - a.push_back(txid.GetHex()); - //a.push_back(Pair("playerdata",tetris_playerobj(playerdata))); - } - } - result.push_back(Pair("playerdata",a)); - result.push_back(Pair("numplayerdata",(int64_t)a.size())); - return(result); -} - -UniValue tetris_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ),a(UniValue::VARR),b(UniValue::VARR); uint256 txid,hashBlock,gametxid,tokenid,playertxid; int32_t vout,maxplayers,gameheight,numvouts; CPubKey tetrispk,mypk; char coinaddr[64]; CTransaction tx,gametx; int64_t buyin; - std::vector > addressIndex; - //std::vector > unspentOutputs; - tetrispk = GetUnspendable(cp,0); - mypk = pubkey2pk(Mypubkey()); - GetCCaddress1of2(cp,coinaddr,tetrispk,mypk); - //SetCCunspents(unspentOutputs,coinaddr); - SetCCtxids(addressIndex,coinaddr); - tetris_univalue(result,"games",-1,-1); - for (std::vector >::const_iterator it=addressIndex.begin(); it!=addressIndex.end(); it++) - //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 ( vout == 0 ) - { - if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 1 ) - { - if ( tetris_registeropretdecode(gametxid,tokenid,playertxid,tx.vout[numvouts-1].scriptPubKey) == 'R' ) - { - if ( tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,gametxid,0) == 0 ) - { - if ( CCgettxout(txid,vout,1,0) < 0 ) - b.push_back(gametxid.GetHex()); - else a.push_back(gametxid.GetHex()); - } - } - } - } - } - result.push_back(Pair("pastgames",b)); - result.push_back(Pair("games",a)); - result.push_back(Pair("numgames",(int64_t)(a.size()+b.size()))); - return(result); -} - -UniValue tetris_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params) -{ - UniValue result(UniValue::VOBJ); int32_t n; char *namestr = 0; - tetris_univalue(result,"setname",-1,-1); - if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 ) - { - if ( n > 0 ) - { - if ( (namestr= jstri(params,0)) != 0 ) - { - result.push_back(Pair("result","success")); - result.push_back(Pair("pname",namestr)); - tetris_pname = namestr; - return(result); - } - } - } - result.push_back(Pair("result","error")); - result.push_back(Pair("error","couldnt get name")); - return(result); -} - -bool tetris_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx) -{ - CScript scriptPubKey; std::vector vopret; uint8_t *script,e,f,funcid,tokentx=0; int32_t i,maxplayers,enabled = 0,decoded=0,regslot,ind,err,dispflag,gameheight,score,numvouts; CTransaction vintx,gametx; CPubKey pk; uint256 hashBlock,gametxid,txid,tokenid,batontxid,playertxid,ptxid; int64_t buyin,cashout; std::vector playerdata,keystrokes; std::string symbol,pname; - if ( strcmp(ASSETCHAINS_SYMBOL,"ROGUE") == 0 ) - { - if (height < 21274 ) - return(true); - else if ( height > 50000 ) - enabled = 1; - } else enabled = 1; - if ( (numvouts= tx.vout.size()) > 1 ) - { - txid = tx.GetHash(); - scriptPubKey = tx.vout[numvouts-1].scriptPubKey; - GetOpReturnData(scriptPubKey,vopret); - if ( vopret.size() > 2 ) - { - script = (uint8_t *)vopret.data(); - funcid = script[1]; - if ( (e= script[0]) == EVAL_TOKENS ) - { - tokentx = funcid; - if ( (funcid= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) == 0 ) - { - if ( (funcid= tetris_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) == 0 ) - { - fprintf(stderr,"ht.%d couldnt decode tokens opret (%c)\n",height,script[1]); - } else e = EVAL_TETRIS, decoded = 1; - } else e = EVAL_TETRIS, decoded = 1; - } - if ( e == EVAL_TETRIS ) - { - //fprintf(stderr,"ht.%d tetris.(%c)\n",height,script[1]); - if ( decoded == 0 ) - { - switch ( funcid ) - { - case 'G': // seems just need to make sure no vout abuse is left to do - gametx = tx; - gametxid = tx.GetHash(); - gameheight = height; - if ( (err= tetris_isvalidgame(cp,gameheight,gametx,buyin,maxplayers,zeroid,0)) != 0 ) - { - fprintf(stderr,"height.%d %s tetris_isvalidgame error.%d\n",height,gametxid.GetHex().c_str(),err); - return eval->Invalid("invalid gametxid"); - } - //fprintf(stderr,"height.%d %s tetris_isvalidgame\n",height,gametxid.GetHex().c_str()); - return(true); - break; - case 'R': - if ( (funcid= tetris_registeropretdecode(gametxid,tokenid,playertxid,scriptPubKey)) != 'R' ) - { - return eval->Invalid("couldnt decode register opret"); - } - // baton is created - // validation is done below - break; - case 'K': - if ( (funcid= tetris_keystrokesopretdecode(gametxid,batontxid,pk,keystrokes,scriptPubKey)) != 'K' ) - { - return eval->Invalid("couldnt decode keystrokes opret"); - } - // spending the baton proves it is the user if the pk is the signer - return(true); - break; - case 'H': case 'Q': - // done in the next switch statement as there are some H/Q tx with playerdata which would skip this section - break; - default: - return eval->Invalid("illegal tetris non-decoded funcid"); - break; - } - } - switch ( funcid ) - { - case 'R': // register - // verify vout amounts are as they should be and no vins that shouldnt be - return(true); - case 'H': // win - case 'Q': // bailout - if ( (f= tetris_highlanderopretdecode(gametxid,tokenid,regslot,pk,playerdata,symbol,pname,scriptPubKey)) != funcid ) - { - //fprintf(stderr,"height.%d couldnt decode H/Q opret\n",height); - //if ( height > 20000 ) - return eval->Invalid("couldnt decode H/Q opret"); - } - // verify pk belongs to this tx - if ( tokentx == 'c' && playerdata.size() > 0 ) - { - static char laststr[512]; char cashstr[512]; - if ( tetris_playerdata_validate(&cashout,ptxid,cp,playerdata,gametxid,pk) < 0 ) - { - sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d gametxid.%s player.%s invalid playerdata[%d]\n",tokentx,decoded,height,gametxid.GetHex().c_str(),ptxid.GetHex().c_str(),(int32_t)playerdata.size()); - if ( strcmp(laststr,cashstr) != 0 ) - { - strcpy(laststr,cashstr); - fprintf(stderr,"%s\n",cashstr); - } - if ( enabled != 0 ) - return eval->Invalid("mismatched playerdata"); - } - if ( funcid == 'H' ) - cashout *= 2; - sprintf(cashstr,"tokentx.(%c) decoded.%d ht.%d txid.%s %.8f vs vout2 %.8f",tokentx,decoded,height,txid.GetHex().c_str(),(double)cashout/COIN,(double)tx.vout[2].nValue/COIN); - if ( strcmp(laststr,cashstr) != 0 ) - { - strcpy(laststr,cashstr); - fprintf(stderr,"%s\n",cashstr); - } - if ( enabled != 0 && tx.vout[2].nValue != cashout ) - return eval->Invalid("mismatched cashout amount"); - } - if ( funcid == 'Q' ) - { - // verify vin/vout - } - else // 'H' - { - // verify vin/vout and proper payouts - } - return(true); - break; - default: - return eval->Invalid("illegal tetris funcid"); - break; - } - } else return eval->Invalid("illegal evalcode"); - } else return eval->Invalid("opret too small"); - } else return eval->Invalid("not enough vouts"); - return(true); -} -#endif - diff --git a/src/gui/komodoku/README.md b/src/gui/komodoku/README.md new file mode 100644 index 000000000..8a3778ea0 --- /dev/null +++ b/src/gui/komodoku/README.md @@ -0,0 +1,27 @@ +About +----- +Komodo SudokuCC GUI + +Just solve Sudoku and earn SUDOKU coins! + +![alt text](https://i.imgur.com/std99XW.png) + +To run you need up and running SUDOKU chain daemon built from latest https://github.com/jl777/komodo/tree/FSM and started with valid for your wallet pubkey in `-pubkey=` param. + +SUDOKU chain params: +```./komodod -ac_name=SUDOKU -ac_supply=1000000 -pubkey= -addnode=5.9.102.210 -gen -genproclimit=1 -ac_cclib=sudoku -ac_perc=10000000 -ac_reward=100000000 -ac_cc=60000 -ac_script=2ea22c80203d1579313abe7d8ea85f48c65ea66fc512c878c0d0e6f6d54036669de940febf8103120c008203000401cc &``` + +1) install dependencies: + +``` +$ sudo apt-get install python-pygame libgnutls28-dev +$ pip install requests wheel slick-bitcoinrpc pygame +``` + +2) and then start: + +``` +$ git clone https://github.com/tonymorony/Komodoku +$ cd Komodoku +$ python Sudoku.py +``` diff --git a/src/gui/komodoku/Roboto-Light.ttf b/src/gui/komodoku/Roboto-Light.ttf new file mode 100755 index 000000000..664e1b2f9 Binary files /dev/null and b/src/gui/komodoku/Roboto-Light.ttf differ diff --git a/src/gui/komodoku/Sudoku.py b/src/gui/komodoku/Sudoku.py new file mode 100644 index 000000000..7b46d93fc --- /dev/null +++ b/src/gui/komodoku/Sudoku.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python + +# Copyright (C) 2010 Paul Bourke +# Copyright (C) 2019 Anton Lysakov +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import pygame +import sys +import random +import sudoku_kmdlib +import time + +class PyGameBoard(): + """Represents the game's frontend using pygame""" + + def __init__(self, engine, windowSize, gridValues, timestampValues): + pygame.init() + pygame.display.set_caption('Sudoku') + self.__engine = engine + self.__gridValues = gridValues + self.__timestampValues = timestampValues + self.__screen = pygame.display.set_mode(windowSize) + background = pygame.image.load(sys.path[0] + '/background.png').convert() + board = pygame.image.load(sys.path[0] + '/board.png') + boardX = boardY = 10 + self.__screen.blit(background, (0, 0)) + self.__screen.blit(board, (boardX, boardY)) + self.__tiles = self.__createTiles(boardX, boardY) + self.__drawUI() + self.__draw() + + def __draw(self): + """Handles events and updates display buffer""" + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + sys.exit() + elif event.type == pygame.MOUSEBUTTONUP and event.button == 1: + self.__handleMouse(event.pos) + elif (event.type == pygame.KEYUP): + self.__handleKeyboard(event.key) + pygame.display.flip() + + def __drawUI(self): + '''Draws the text buttons along the right panel''' + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 28) + font.set_underline(True) + self.__titleText = font.render('Sudoku', 1, (0, 0, 0)) + self.__titleTextRect = self.__titleText.get_rect() + self.__titleTextRect.centerx = 445 + self.__titleTextRect.centery = 30 + self.__screen.blit(self.__titleText, self.__titleTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 14) + self.__titleText = font.render('TonyL 2019', 1, (0, 0, 0)) + self.__titleTextRect = self.__titleText.get_rect() + self.__titleTextRect.centerx = 445 + self.__titleTextRect.centery = 55 + self.__screen.blit(self.__titleText, self.__titleTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + self.__newGameText = font.render('-New Game-', 1, (0, 0, 0)) + self.__newGameTextRect = self.__newGameText.get_rect() + self.__newGameTextRect.centerx = 495 + self.__newGameTextRect.centery = 180 + self.__screen.blit(self.__newGameText, self.__newGameTextRect) + + self.__solveText = font.render('-Check Balance-', 1, (0, 0, 0)) + self.__solveTextRect = self.__solveText.get_rect() + self.__solveTextRect.centerx = 495 + self.__solveTextRect.centery = 220 + self.__screen.blit(self.__solveText, self.__solveTextRect) + + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + self.__checkText = font.render('-Check Solution-', 1, (0, 0, 0)) + self.__checkTextRect = self.__checkText.get_rect() + self.__checkTextRect.centerx = 495 + self.__checkTextRect.centery = 260 + self.__screen.blit(self.__checkText, self.__checkTextRect) + + def __handleKeyboard(self, key): + """Get key pressed and update the game board""" + validKeys = {pygame.K_0: "0", pygame.K_1: "1", pygame.K_2: "2", + pygame.K_3: "3", pygame.K_4: "4", pygame.K_5: "5", + pygame.K_6: "6", pygame.K_7: "7", pygame.K_8: "8", + pygame.K_9: "9", pygame.K_BACKSPACE: "", pygame.K_DELETE: ""} + if key == pygame.K_ESCAPE: + sys.exit() + elif key in validKeys: + i = self.__currentTile.getGridLoc()[0] + j = self.__currentTile.getGridLoc()[1] + cell_num = 9 * i + (j + 1) + self.__currentTile.setFontColor(pygame.color.THECOLORS['blue']) + self.__currentTile.updateValue(validKeys[key]) + self.__gridValues[i][j] = self.__currentTile.getValue() + self.__timestampValues[cell_num] = int(round(time.time())) + + def __handleMouse(self, (x, y)): + for row in self.__tiles: + for tile in row: + if tile.getRect().collidepoint(x, y): + if not tile.isReadOnly(): + tile.highlight(pygame.color.THECOLORS['lightyellow']) + if self.__currentTile.isCorrect(): + self.__currentTile.unhighlight() + else: + self.__currentTile.highlight((255, 164, 164)) + self.__currentTile = tile + if self.__newGameTextRect.collidepoint(x, y): + self.__engine.startNewGame() + elif self.__solveTextRect.collidepoint(x, y): + self.__engine.getSolution() + elif self.__checkTextRect.collidepoint(x, y): + ret = self.__engine.checkSolution(self.__gridValues, self.__timestampValues) + + def __updateBoard(self, gridValues): + for i in range(9): + for j in range(9): + self.__tiles[i][j].updateValue(gridValues[i][j]) + + def __unhightlightBoard(self): + for i in range(9): + for j in range(9): + self.__tiles[i][j].unhighlight() + + def __createTiles(self, initX=0, initY=0): + """Set up a list of tiles corresponding to the grid, along with + each ones location coordinates on the board""" + square_size = 40 + tiles = list() + x = y = 0 + for i in range(0, 9): + row = list() + for j in range(0, 9): + if j in (0, 1, 2): + x = (j * 41) + (initX + 2) + if j in (3, 4, 5): + x = (j * 41) + (initX + 6) + if j in (6, 7, 8): + x = (j * 41) + (initX + 10) + if i in (0, 1, 2): + y = (i * 41) + (initY + 2) + if i in (3, 4, 5): + y = (i * 41) + (initY + 6) + if i in (6, 7, 8): + y = (i * 41) + (initY + 10) + tile = Tile(self.__gridValues[i][j], (x, y), (i, j), square_size) + row.append(tile) + tiles.append(row) + self.__currentTile = tiles[0][0] + return tiles + + +class Tile(): + """Represents a graphical tile on the board""" + + def __init__(self, value, coords, gridLoc, size): + xpos = coords[0] + ypos = coords[1] + self.__fontColor = pygame.color.THECOLORS["black"] + self.__readOnly = False + self.__colorSquare = pygame.Surface((size, size)).convert() + self.__colorSquare.fill(pygame.color.THECOLORS['white'], None, pygame.BLEND_RGB_ADD) + self.__colorSquareRect = self.__colorSquare.get_rect() + self.__colorSquareRect = self.__colorSquareRect.move(xpos + 1, ypos + 1) + self.__value = value + self.__gridLoc = gridLoc + self.__screen = pygame.display.get_surface() + self.__rect = pygame.Rect(xpos, ypos, size, size) + self.__isCorrect = True + if self.__value is not '-': + self.__readOnly = True + self.__draw() + + def updateValue(self, value): + self.__value = value + self.__draw() + + def isCorrect(self): + return self.__isCorrect + + def setCorrect(self, isCorrect): + self.__isCorrect = isCorrect + + def setFontColor(self, fontColor): + self.__fontColor = fontColor + + def getValue(self): + return self.__value + + def getRect(self): + return self.__rect + + def getGridLoc(self): + return self.__gridLoc + + def isReadOnly(self): + return self.__readOnly + + def highlight(self, color): + if self.__readOnly is True: + return + self.__colorSquare.fill(color) + self.__draw() + + def unhighlight(self): + self.__colorSquare.fill((255, 225, 255), None, pygame.BLEND_RGB_ADD) + self.__draw() + + def __draw(self): + value = self.__value + if self.__value == '-': + value = '' + font = pygame.font.Font(sys.path[0] + '/Roboto-Light.ttf', 24) + text = font.render(str(value), 1, self.__fontColor) + textpos = text.get_rect() + textpos.centerx = self.__rect.centerx + textpos.centery = self.__rect.centery + self.__screen.blit(self.__colorSquare, self.__colorSquareRect) + self.__screen.blit(text, textpos) + + +class Sudoku: + """Represents the game's backend and logic""" + + def __init__(self, puzzleFile, rpc_connection): + self.__puzzleFile = puzzleFile + self.__rpc_connection = rpc_connection + self.startNewGame() + + def startNewGame(self): + self.__linePuzzle = self.__loadPuzzle(self.__puzzleFile) + gridValues = self.lineToGrid(self.__linePuzzle) + # prefill 0 timestamps for already known numbers + timestampValues = self.prefill_timestamps(gridValues) + board = PyGameBoard(self, (600, 400), gridValues, timestampValues) + board.setValues(gridValues) + + def __loadPuzzle(self, listName): + self.__chosen_puzzle = random.choice(listName) + puzzle = self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["unsolved"] + print "Puzzle ID: " + self.__chosen_puzzle + print "Reward amount: " + str(self.__rpc_connection.cclib("txidinfo", "17", '"%22' + self.__chosen_puzzle + '%22"')["amount"]) + ret = [] + linePuzzle = str(puzzle) + for i in linePuzzle: + ret.append(i) + return ret + + def gridToLine(self, grid): + linePuzzle = '' + for i in range(9): + for j in range(9): + linePuzzle += grid[i][j] + return linePuzzle + + def lineToGrid(self, linePuzzle): + assert (len(linePuzzle) == 81) + grid = [] + for i in xrange(0, 81, 9): + grid.append(linePuzzle[i:i + 9]) + return grid + + def getSolution(self): + balance = self.__rpc_connection.cclibaddress("17")["mybalance"] + print "Your balance: " + str(balance) + + def __solve(self, linePuzzle): + linePuzzle = ''.join(linePuzzle) + i = linePuzzle.find('-') + if i == -1: + return linePuzzle + + excluded_numbers = set() + for j in range(81): + if self.sameRow(i, j) or self.sameCol(i, j) or self.sameBlock(i, j): + excluded_numbers.add(linePuzzle[j]) + + for m in '123456789': + if m not in excluded_numbers: + funcRet = self.__solve(linePuzzle[:i] + m + linePuzzle[i + 1:]) + if funcRet is not None: + return funcRet + + def prefill_timestamps(self, grid): + timestamps = {} + for i in range(9): + for j in range(9): + if grid[i][j] != '-': + cell_num = 9 * i + ( j + 1 ) + timestamps[cell_num] = 0 + return timestamps + + def sameRow(self, i, j): + return (i / 9 == j / 9) + + def sameCol(self, i, j): + return (i - j) % 9 == 0 + + def sameBlock(self, i, j): + return (i / 27 == j / 27 and i % 9 / 3 == j % 9 / 3) + + def checkSolution(self, attemptGrid, timestampValues): + # [%22%22,%22%22,t0,t1,t2,...] + attemptLine = self.gridToLine(attemptGrid) + + #print attemptLine + #print timestampValues + timestampsline = "" + for timestamp in timestampValues.values(): + timestampsline += "," + timestampsline += str(timestamp) + arg_line = "[%22"+self.__chosen_puzzle+"%22,%22"+attemptLine+"%22"+timestampsline+"]" + print arg_line + try: + solution_info = self.__rpc_connection.cclib("solution", "17", '"' + arg_line + '"') + print solution_info + solution_txid = self.__rpc_connection.sendrawtransaction(solution_info["hex"]) + print "Solution accepted!" + print solution_txid + except Exception as e: + print(e) + print(solution_info) + solution_txid = 'error' + return solution_txid + +def main(): + while True: + # Assetchain hardcoded here + chain = 'SUDOKU' + try: + print 'Welcome to the Komodo SudokuCC' + rpc_connection = sudoku_kmdlib.def_credentials(chain) + pending_puzzles = rpc_connection.cclib("pending", "17")["pending"] + puzzle_list = [] + for puzzle in pending_puzzles: + puzzle_list.append(puzzle["txid"]) + + except Exception as e: + #print rpc_connection + print e + print 'Cant connect to SUDOKU Daemon! Please re-check if it up' + sys.exit() + else: + print 'Succesfully connected!\n' + break + newGame = Sudoku(puzzle_list, rpc_connection) + +if __name__ == '__main__': + main() diff --git a/src/gui/komodoku/background.png b/src/gui/komodoku/background.png new file mode 100644 index 000000000..dc4844a0b Binary files /dev/null and b/src/gui/komodoku/background.png differ diff --git a/src/gui/komodoku/board.png b/src/gui/komodoku/board.png new file mode 100644 index 000000000..bd77ca419 Binary files /dev/null and b/src/gui/komodoku/board.png differ diff --git a/src/gui/komodoku/sudoku_kmdlib.py b/src/gui/komodoku/sudoku_kmdlib.py new file mode 100644 index 000000000..a2b2aa239 --- /dev/null +++ b/src/gui/komodoku/sudoku_kmdlib.py @@ -0,0 +1,41 @@ +import platform +import os +import re +import random +from slickrpc import Proxy + + +# define function that fetchs rpc creds from .conf +def def_credentials(chain): + rpcport =''; + operating_system = platform.system() + if operating_system == 'Darwin': + ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo' + elif operating_system == 'Linux': + ac_dir = os.environ['HOME'] + '/.komodo' + elif operating_system == 'Windows': + ac_dir = '%s/komodo/' % os.environ['APPDATA'] + if chain == 'KMD': + coin_config_file = str(ac_dir + '/komodo.conf') + else: + coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf') + with open(coin_config_file, 'r') as f: + for line in f: + l = line.rstrip() + if re.search('rpcuser', l): + rpcuser = l.replace('rpcuser=', '') + elif re.search('rpcpassword', l): + rpcpassword = l.replace('rpcpassword=', '') + elif re.search('rpcport', l): + rpcport = l.replace('rpcport=', '') + if len(rpcport) == 0: + if chain == 'KMD': + rpcport = 7771 + else: + print("rpcport not in conf file, exiting") + print("check "+coin_config_file) + exit(1) + + return(Proxy("http://%s:%s@127.0.0.1:%d"%(rpcuser, rpcpassword, int(rpcport)))) + + diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index e76da09ec..eefccd32a 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -201,6 +201,9 @@ try_again: curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback + //curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + //curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, 2); + if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); @@ -247,13 +250,13 @@ try_again: numretries++; if ( specialcase != 0 ) { - printf("<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); + fprintf(stderr,"<<<<<<<<<<< bitcoind_RPC.(%s): BTCD.%s timeout params.(%s) s.ptr.(%s) err.%d\n",url,command,params,s.ptr,res); free(s.ptr); return(0); } else if ( numretries >= 1 ) { - //printf("Maximum number of retries exceeded!\n"); + fprintf(stderr,"Maximum number of retries exceeded!\n"); free(s.ptr); return(0); } @@ -1234,7 +1237,7 @@ uint64_t komodo_commission(const CBlock *pblock,int32_t height) n = pblock->vtx[i].vout.size(); for (j=0; j 100000 && ASSETCHAINS_STAKED != 0 && txn_count > 1 && i == txn_count-1 && j == n-1 ) + if ( height > 150000 && ASSETCHAINS_STAKED != 0 && txn_count > 1 && i == txn_count-1 && j == n-1 ) break; //fprintf(stderr,"(%d %.8f).%d ",i,dstr(pblock->vtx[i].vout[j].nValue),j); if ( i != 0 || j != 1 ) diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 23f291a20..0f053f6ca 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -50,7 +50,7 @@ extern uint64_t ASSETCHAINS_TIMELOCKGTE; extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH,ASSETCHAINS_EQUIHASH,KOMODO_INITDONE; extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,KOMODO_ON_DEMAND,KOMODO_PASSPORT_INITDONE,ASSETCHAINS_STAKED; -extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_LASTERA; +extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_LASTERA,ASSETCHAINS_CBOPRET; extern bool VERUS_MINTBLOCKS; extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[]; extern const char *ASSETCHAINS_ALGORITHMS[]; diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 36409e67d..932efd051 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -1547,3 +1547,547 @@ void komodo_passport_iteration() printf("READY for %s RPC calls at %u! done PASSPORT %s refid.%d\n",ASSETCHAINS_SYMBOL,(uint32_t)time(NULL),ASSETCHAINS_SYMBOL,refid); } } + +extern std::vector Mineropret; // opreturn data set by the data gathering code +#define PRICES_MAXCHANGE (COIN / 100) // maximum acceptable change, set at 1% +#define PRICES_SIZEBIT0 (sizeof(uint32_t) * 4) // 4 uint32_t unixtimestamp, BTCUSD, BTCGBP and BTCEUR + +// komodo_heightpricebits() extracts the price data in the coinbase for nHeight +int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight) +{ + CBlockIndex *pindex; CBlock block; CTransaction tx; int32_t numvouts; std::vector vopret; + if ( (pindex= komodo_chainactive(nHeight)) != 0 ) + { + if ( komodo_blockload(block,pindex) == 0 ) + { + tx = block.vtx[0]; + numvouts = (int32_t)tx.vout.size(); + GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret); + if ( vopret.size() >= PRICES_SIZEBIT0 ) + { + memcpy(prevbits,vopret.data(),vopret.size()); + return(0); + } + } + } + fprintf(stderr,"couldnt get pricebits for %d\n",nHeight); + return(-1); +} + +/* + komodo_pricenew() is passed in a reference price, the change tolerance and the proposed price. it needs to return a clipped price if it is too big and also set a flag if it is at or above the limit + */ +uint32_t komodo_pricenew(char *maxflagp,uint32_t price,uint32_t refprice,int64_t tolerance) +{ + uint64_t highprice,lowprice; + if ( refprice < 2 ) + return(0); + highprice = ((uint64_t)refprice * (COIN + tolerance)) / COIN; // calc highest acceptable price + lowprice = ((uint64_t)refprice * (COIN - tolerance)) / COIN; // and lowest + if ( highprice == refprice ) + highprice++; + if ( lowprice == refprice ) + lowprice--; + if ( price >= highprice ) + { + fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + if ( price > highprice ) // return non-zero only if we violate the tolerance + { + *maxflagp = 2; + return(highprice); + } + *maxflagp = 1; + } + else if ( price <= lowprice ) + { + //fprintf(stderr,"low %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance); + if ( price < lowprice ) + { + *maxflagp = -2; + return(lowprice); + } + *maxflagp = -1; + } + return(0); +} + +// komodo_pricecmp() returns -1 if any of the prices are beyond the tolerance +int32_t komodo_pricecmp(int32_t nHeight,int32_t n,char *maxflags,uint32_t *pricebitsA,uint32_t *pricebitsB,int64_t tolerance) +{ + int32_t i; uint32_t newprice; + for (i=1; i newprice.%u out of tolerance maxflag.%d\n",nHeight,i,n,pricebitsB[i],pricebitsA[i],newprice,maxflags[i]); + return(-1); + } + } + return(0); +} + +// komodo_priceclamp() clamps any price that is beyond tolerance +int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int64_t tolerance) +{ + int32_t i; uint32_t newprice; char maxflags[2048]; + memset(maxflags,0,sizeof(maxflags)); + for (i=1; i %u\n",i,n,refprices[i],pricebits[i],newprice); + pricebits[i] = newprice; + } + } + return(0); +} + +// komodo_mineropret() returns a valid pricedata to add to the coinbase opreturn for nHeight +CScript komodo_mineropret(int32_t nHeight) +{ + CScript opret; char maxflags[2048]; uint32_t pricebits[2048],prevbits[2048]; int32_t maxflag,i,n,numzero=0; + if ( Mineropret.size() >= PRICES_SIZEBIT0 ) + { + n = (int32_t)(Mineropret.size() / sizeof(uint32_t)); + numzero = 1; + while ( numzero > 0 ) + { + memcpy(pricebits,Mineropret.data(),Mineropret.size()); + for (i=numzero=0; i vopret; char maxflags[2048]; double btcusd,btcgbp,btceur; uint32_t localbits[2048],pricebits[2048],prevbits[2048],newprice; int32_t i,maxflag,lag,lag2,n; uint32_t now = (uint32_t)time(NULL); + if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 ) + { + GetOpReturnData(scriptPubKey,vopret); + if ( vopret.size() >= PRICES_SIZEBIT0 ) + { + n = (int32_t)(vopret.size() / sizeof(uint32_t)); + memcpy(pricebits,vopret.data(),Mineropret.size()); + memset(maxflags,0,sizeof(maxflags)); + if ( nHeight > 1 ) + { + lag = (int32_t)(now - pricebits[0]); + lag2 = (int32_t)(komodo_heightstamp(nHeight-1) - pricebits[0]); + if ( lag < -60 ) // avoid data from future + { + fprintf(stderr,"now.%u htstamp.%u - pricebits[0] %u -> lag.%d\n",now,komodo_heightstamp(nHeight-1),pricebits[0],lag2); + return(-1); + } + // else need to check against current blocktime to prevent pricebits[0] games + btcusd = (double)pricebits[1]/10000; + btcgbp = (double)pricebits[2]/10000; + btceur = (double)pricebits[3]/10000; + fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2); + if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 ) + { + if ( nHeight < 500 ) + { + for (i=0; i= PRICES_SIZEBIT0 ) + { + memcpy(localbits,Mineropret.data(),Mineropret.size()); + if ( nHeight < 500 ) + { + for (i=0; i 0 && localbits[i] < prevbits[i] ) + return(-1); + else if ( maxflag < 0 && localbits[i] > prevbits[i] ) + return(-1); + } + } + } + } + return(0); + } else fprintf(stderr,"wrong size %d vs %d, scriptPubKey size %d [%02x]\n",(int32_t)vopret.size(),(int32_t)Mineropret.size(),(int32_t)scriptPubKey.size(),scriptPubKey[0]); + return(-1); + } + return(0); +} + +char *nonportable_path(char *str) +{ + int32_t i; + for (i=0; str[i]!=0; i++) + if ( str[i] == '/' ) + str[i] = '\\'; + return(str); +} + +char *portable_path(char *str) +{ +#ifdef _WIN32 + return(nonportable_path(str)); +#else +#ifdef __PNACL + /*int32_t i,n; + if ( str[0] == '/' ) + return(str); + else + { + n = (int32_t)strlen(str); + for (i=n; i>0; i--) + str[i] = str[i-1]; + str[0] = '/'; + str[n+1] = 0; + }*/ +#endif + return(str); +#endif +} + +void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) +{ + FILE *fp; + long filesize,buflen = *allocsizep; + uint8_t *buf = *bufp; + *lenp = 0; + if ( (fp= fopen(portable_path(fname),"rb")) != 0 ) + { + fseek(fp,0,SEEK_END); + filesize = ftell(fp); + if ( filesize == 0 ) + { + fclose(fp); + *lenp = 0; + //printf("loadfile null size.(%s)\n",fname); + return(0); + } + if ( filesize > buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); + } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; + } + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); +} + +void *filestr(long *allocsizep,char *_fname) +{ + long filesize = 0; char *fname,*buf = 0; void *retptr; + *allocsizep = 0; + fname = (char *)malloc(strlen(_fname)+1); + strcpy(fname,_fname); + retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); + free(fname); + return(retptr); +} + +cJSON *send_curl(char *url,char *fname) +{ + long fsize; char curlstr[1024],*jsonstr; cJSON *json=0; + sprintf(curlstr,"wget -q \"%s\" -O %s",url,fname); + if ( system(curlstr) == 0 ) + { + if ( (jsonstr= (char *)filestr((long *)&fsize,fname)) != 0 ) + { + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + } + return(json); +} + +// get_urljson just returns the JSON returned by the URL using issue_curl + +#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0) + +const char *Cryptos[] = { "KMD", "ETH", "LTC", "BCHABC", "XMR", "IOTA", "DASH", "XEM", "ZEC", "WAVES", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "STEEM", "ENJ", "STRAT" }; + +const char *Forex[] = +{ "BGN","NZD","ILS","RUB","CAD","PHP","CHF","AUD","JPY","TRY","HKD","MYR","HRK","CZK","IDR","DKK","NOK","HUF","GBP","MXN","THB","ISK","ZAR","BRL","SGD","PLN","INR","KRW","RON","CNY","SEK","EUR" +}; + +/* +const char *Techstocks[] = +{ "AAPL","ADBE","ADSK","AKAM","AMD","AMZN","ATVI","BB","CDW","CRM","CSCO","CYBR","DBX","EA","FB","GDDY","GOOG","GRMN","GSAT","HPQ","IBM","INFY","INTC","INTU","JNPR","MSFT","MSI","MU","MXL","NATI","NCR","NFLX","NTAP","NVDA","ORCL","PANW","PYPL","QCOM","RHT","S","SHOP","SNAP","SPOT","SYMC","SYNA","T","TRIP","TWTR","TXN","VMW","VOD","VRSN","VZ","WDC","XRX","YELP","YNDX","ZEN" +}; +const char *Metals[] = { "XAU", "XAG", "XPT", "XPD", }; + +const char *Markets[] = { "DJIA", "SPX", "NDX", "VIX" }; +*/ + +cJSON *get_urljson(char *url) +{ + char *jsonstr; cJSON *json = 0; + if ( (jsonstr= issue_curl(url)) != 0 ) + { + //fprintf(stderr,"(%s) -> (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + return(json); +} + +uint32_t get_stockprice(const char *symbol) +{ + char url[512]; cJSON *json,*obj; uint32_t high,low,price = 0; + sprintf(url,"https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=%s&interval=15min&apikey=%s",symbol,NOTARY_PUBKEY.data()+50); + if ( (json= get_urljson(url)) != 0 ) + { + if ( (obj= jobj(json,(char *)"Time Series (15min)")) != 0 ) + { + high = jdouble(jitem(obj,0),(char *)"2. high")*10000 + 0.000049; + low = jdouble(jitem(obj,0),(char *)"3. low")*10000 + 0.000049; + price = (high + low) / 2; + } + free_json(json); + } + return(price); +} + +uint32_t get_dailyfx(uint32_t *prices) +{ + //{"base":"USD","rates":{"BGN":1.74344803,"NZD":1.471652701,"ILS":3.6329113924,"RUB":65.1997682296,"CAD":1.3430201462,"USD":1.0,"PHP":52.8641469068,"CHF":0.9970582992,"AUD":1.4129078267,"JPY":110.6792654662,"TRY":5.6523444464,"HKD":7.8499732573,"MYR":4.0824567659,"HRK":6.6232840078,"CZK":22.9862720628,"IDR":14267.4986628633,"DKK":6.6551078624,"NOK":8.6806917454,"HUF":285.131039401,"GBP":0.7626582278,"MXN":19.4183455161,"THB":31.8702085933,"ISK":122.5708682475,"ZAR":14.7033339276,"BRL":3.9750401141,"SGD":1.3573720806,"PLN":3.8286682118,"INR":69.33187734,"KRW":1139.1602781244,"RON":4.2423783206,"CNY":6.7387234801,"SEK":9.3385630237,"EUR":0.8914244963},"date":"2019-03-28"} + char url[512],*datestr; cJSON *json,*rates; int32_t i; uint32_t datenum=0,price = 0; + sprintf(url,"https://api.openrates.io/latest?base=USD"); + if ( (json= send_curl(url,(char *)"dailyfx")) != 0 ) + { + if ( (rates= jobj(json,(char *)"rates")) != 0 ) + { + for (i=0; i 333 ) + ASSETCHAINS_CBOPRET = 7; + size = PRICES_SIZEBIT0; + if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) + size += sizeof(forexprices); + if ( (ASSETCHAINS_CBOPRET & 4) != 0 ) + size += sizeof(cryptoprices); + if ( Mineropret.size() < size ) + Mineropret.resize(size); + size = PRICES_SIZEBIT0; + if ( now > lastbtc+120 && get_btcusd(pricebits) == 0 ) + { + memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0); + lastbtc = (uint32_t)time(NULL); + } + if ( (ASSETCHAINS_CBOPRET & 2) != 0 ) + { + if ( now > lasttime+3600*5 || forexprices[0] == 0 ) + { + get_dailyfx(forexprices); + memcpy(&Mineropret.data()[size],forexprices,sizeof(forexprices)); + lasttime = (uint32_t)time(NULL); + } + size += sizeof(forexprices); + } + if ( (ASSETCHAINS_CBOPRET & 4) != 0 ) + { + if ( now > lastcrypto+100 ) + { + get_cryptoprices(cryptoprices,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos))); + memcpy(&Mineropret.data()[size],cryptoprices,sizeof(cryptoprices)); + lastcrypto = (uint32_t)time(NULL); + } + size += sizeof(cryptoprices); + } + //int32_t i; for (i=0; i Mineropret; char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096],NOTARYADDRS[64][36]; uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT,ASSETCHAINS_BEAMPORT,ASSETCHAINS_CODAPORT; @@ -66,7 +67,7 @@ int64_t MAX_MONEY = 200000000 * 100000000LL; // spec will use an op_return with CLTV at front and anything after |OP_RETURN|PUSH of rest|OPRETTYPE_TIMELOCK|script| #define _ASSETCHAINS_TIMELOCKOFF 0xffffffffffffffff uint64_t ASSETCHAINS_TIMELOCKGTE = _ASSETCHAINS_TIMELOCKOFF; -uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0; +uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0,ASSETCHAINS_CBOPRET=0; uint64_t ASSETCHAINS_LASTERA = 1; uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS]; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index c1f488c5c..a91dae1e8 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1664,11 +1664,12 @@ uint64_t komodo_ac_block_subsidy(int nHeight) } extern int64_t MAX_MONEY; +void komodo_cbopretupdate(); void komodo_args(char *argv0) { extern const char *Notaries_elected1[][2]; - std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256]; + std::string name,addn,hexstr; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256]; IS_KOMODO_NOTARY = GetBoolArg("-notary", false); IS_STAKED_NOTARY = GetArg("-stakednotary", -1); if ( IS_STAKED_NOTARY != -1 && IS_KOMODO_NOTARY == true ) { @@ -1810,6 +1811,16 @@ void komodo_args(char *argv0) ASSETCHAINS_BEAMPORT = GetArg("-ac_beam",0); ASSETCHAINS_CODAPORT = GetArg("-ac_coda",0); ASSETCHAINS_MARMARA = GetArg("-ac_marmara",0); + ASSETCHAINS_CBOPRET = GetArg("-ac_cbopret",0); + hexstr = GetArg("-ac_mineropret",""); + if ( hexstr.size() != 0 ) + { + Mineropret.resize(hexstr.size()/2); + decode_hex(Mineropret.data(),hexstr.size()/2,(char *)hexstr.c_str()); + for (i=0; i 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 ) + if ( ASSETCHAINS_ENDSUBSIDY[0] != 0 || ASSETCHAINS_REWARD[0] != 0 || ASSETCHAINS_HALVING[0] != 0 || ASSETCHAINS_DECAY[0] != 0 || ASSETCHAINS_COMMISSION != 0 || ASSETCHAINS_PUBLIC != 0 || ASSETCHAINS_PRIVATE != 0 || ASSETCHAINS_TXPOW != 0 || ASSETCHAINS_FOUNDERS != 0 || ASSETCHAINS_SCRIPTPUB.size() > 1 || ASSETCHAINS_SELFIMPORT.size() > 0 || ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 || ASSETCHAINS_TIMELOCKGTE != _ASSETCHAINS_TIMELOCKOFF|| ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH || ASSETCHAINS_LWMAPOS != 0 || ASSETCHAINS_LASTERA > 0 || ASSETCHAINS_BEAMPORT != 0 || ASSETCHAINS_CODAPORT != 0 || ASSETCHAINS_MARMARA != 0 || nonz > 0 || ASSETCHAINS_CCLIB.size() > 0 || ASSETCHAINS_FOUNDERS_REWARD != 0 || ASSETCHAINS_NOTARY_PAY[0] != 0 || ASSETCHAINS_BLOCKTIME != 60 || ASSETCHAINS_CBOPRET != 0 || Mineropret.size() != 0 ) { fprintf(stderr,"perc %.4f%% ac_pub=[%02x%02x%02x...] acsize.%d\n",dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0],ASSETCHAINS_OVERRIDE_PUBKEY33[1],ASSETCHAINS_OVERRIDE_PUBKEY33[2],(int32_t)ASSETCHAINS_SCRIPTPUB.size()); extraptr = extrabuf; @@ -2048,6 +2059,17 @@ void komodo_args(char *argv0) } if ( ASSETCHAINS_BLOCKTIME != 60 ) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_BLOCKTIME),(void *)&ASSETCHAINS_BLOCKTIME); + if ( Mineropret.size() != 0 ) + { + for (i=0; i 0 && (nHeight & 1) == 0 ) + { + + } + else if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 && tx.vout.size() > 0 ) + { + if ( komodo_opretvalidate(nHeight,tx.vout[tx.vout.size()-1].scriptPubKey) < 0 ) + return(false); + } return(true); } @@ -4111,7 +4120,14 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * GetMainSignals().BlockChecked(*pblock, state); if (!rv) { if (state.IsInvalid()) + { InvalidBlockFound(pindexNew, state); + /*if ( ASSETCHAINS_CBOPRET != 0 ) + { + pindexNew->nStatus &= ~BLOCK_FAILED_MASK; + fprintf(stderr,"reconsiderblock %d\n",(int32_t)pindexNew->GetHeight()); + }*/ + } return error("ConnectTip(): ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); } mapBlockSource.erase(pindexNew->GetBlockHash()); @@ -5202,7 +5218,7 @@ bool AcceptBlockHeader(int32_t *futureblockp,const CBlockHeader& block, CValidat miSelf->second = pindex = AddToBlockIndex(block); if (ppindex) *ppindex = pindex; - if ( pindex != 0 && pindex->nStatus & BLOCK_FAILED_MASK ) + if ( pindex != 0 && (pindex->nStatus & BLOCK_FAILED_MASK) != 0 ) { if ( ASSETCHAINS_CC == 0 )//&& (ASSETCHAINS_PRIVATE == 0 || KOMODO_INSYNC >= Params().GetConsensus().vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight) ) return state.Invalid(error("%s: block is marked invalid", __func__), 0, "duplicate"); diff --git a/src/miner.cpp b/src/miner.cpp index eaba96ee1..f131bc90e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -155,6 +155,7 @@ CScript MarmaraCoinbaseOpret(uint8_t funcid,int32_t height,CPubKey pk); uint64_t komodo_notarypay(CMutableTransaction &txNew, std::vector &NotarisationNotaries, uint32_t timestamp, int32_t height, uint8_t *script, int32_t len); int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); int32_t komodo_getnotarizedheight(uint32_t timestamp,int32_t height, uint8_t *script, int32_t len); +CScript komodo_mineropret(int32_t nHeight); CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32_t gpucount, bool isStake) { @@ -723,7 +724,14 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 fprintf(stderr, "Created notary payment coinbase totalsat.%lu\n",totalsats); } else fprintf(stderr, "vout 2 of notarisation is not OP_RETURN scriptlen.%i\n", scriptlen); } - + if ( ASSETCHAINS_CBOPRET != 0 ) + { + int32_t numv = (int32_t)txNew.vout.size(); + txNew.vout.resize(numv+1); + txNew.vout[numv].nValue = 0; + txNew.vout[numv].scriptPubKey = komodo_mineropret(nHeight); + //printf("autocreate commision/cbopret.%lld vout[%d]\n",(long long)ASSETCHAINS_CBOPRET,(int32_t)txNew.vout.size()); + } pblock->vtx[0] = txNew; pblocktemplate->vTxFees[0] = -nFees; @@ -941,6 +949,7 @@ void komodo_sendmessage(int32_t minpeers,int32_t maxpeers,const char *message,st continue; if ( numsent < minpeers || (rand() % 10) == 0 ) { + //fprintf(stderr,"pushmessage\n"); pnode->PushMessage(message,payload); if ( numsent++ > maxpeers ) break; diff --git a/src/tui/LICENSE b/src/tui/LICENSE new file mode 100644 index 000000000..3300ef648 --- /dev/null +++ b/src/tui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Anton Lysakov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/tui/README.md b/src/tui/README.md new file mode 100644 index 000000000..61e733794 --- /dev/null +++ b/src/tui/README.md @@ -0,0 +1,58 @@ +# Komodo Cryptoconditons Terminal User Interfaces (aka TUIs) + +These tools creating for demonstration and partial automation of Komodo cryptoconditions modules testing. (RogueCC game, AssetsCC, OraclesCC, GatewaysCC, MarmaraCC, ...) + + +Developer installation (on Ubuntu 18.04) : + +Python3 required for execution: + +* `sudo apt-get install python3.6 python3-pip libgnutls28-dev` + +pip packages needed: + +* `pip3 install setuptools wheel slick-bitcoinrpc` +* or `pip3 install -r requirements.txt` + +Starting: + +# TUI for RogueCC + +If you're looking for player 3 in 1 (daemon + game + TUI) multiOS bundle - please check `releases` of this repo. + +`python3 rogue_tui.py` + +![alt text](https://i.imgur.com/gkcxMGt.png) + +# TUI for OraclesCC + +Have files uploader/downloader functionality - also there is a AWS branch for AWS certificates uploading demonstration + +`python3 oracles_cc_tui.py` + +![alt text](https://i.imgur.com/tfHwRqc.png) + +# TUI for GatewaysCC + +![alt text](https://i.imgur.com/c8DPfpp.png) + +`python3 gateways_creation_tui.py` + +`python3 gateways_usage_tui.py` + +At the moment raw version of manual gateway how-to guide can be found here: https://docs.komodoplatform.com/cc/contracts/gateways/scenarios/tutorial.html I advice to read it before you start use this tool to understand the flow. + +# TUI for MarmaraCC + +`python3 marmara_tui.py` + +![alt text](https://i.imgur.com/uonMWHl.png) + +# TUI for AssetsCC (not much finished) + +`python3 assets_cc_tui.py` + +Before execution be sure than daemon for needed AC up. + + + diff --git a/src/tui/lib/logo.txt b/src/tui/lib/logo.txt new file mode 100644 index 000000000..15ace1ad5 --- /dev/null +++ b/src/tui/lib/logo.txt @@ -0,0 +1,39 @@ +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWWWWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xlc:ldOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xo:,........';lxOXNMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMWNKkoc,..................':ox0XWMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMWNKkdc;............................,:ok0NWMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMWNKOdl;'.....................................,cdkKNWMMMMMMMMMMMMMM +MMMMMMMMMMMMMW0c'..............................................';kNMMMMMMMMMMMMM +MMMMMMMMMMMMMK:......................';:c:'......................,kWMMMMMMMMMMMM +MMMMMMMMMMMMXl...................;cdkKNWWNXOdl;'..................;OWMMMMMMMMMMM +MMMMMMMMMMMNo...............,cok0XWMMMMMMMMMMWNKkdc;'..............:KMMMMMMMMMMM +MMMMMMMMMMWx'...........;ox0XWMMMMMMMMMMMMMMMMMMMMWNKko:............lXMMMMMMMMMM +MMMMMMMMMWk,...........lXWMMMMMMMMMMMMWWWWMMMMMMMMMMMMMNx'...........oNMMMMMMMMM +MMMMMMMMW0;...........cKMMMMMMMMMWNXOdl::cdkKNWMMMMMMMMMNo...........'xWMMMMMMMM +MMMMMMMMKc...........;0WMMMMMWN0xl:,........';ldOXWMMMMMMXl...........,OWMMMMMMM +MMMMMMMXl...........,kWMMMMMMKl..................;OWMMMMMMK:...........;0MMMMMMM +MMMMMMNd...........'xNMMMMMMXl....................:0WMMMMMWO;...........cKMMMMMM +MMMMMNx'...........oNMMMMMMNd......................cKMMMMMMWk'...........lXMMMMM +MMMMWO,...........lXMMMMMMWx'.......................oXMMMMMMNd'...........dNMMMM +MMMMXc...........,OWMMMMMMK:........................,kWMMMMMMKc...........;0MMMM +MMMMWx'...........oXMMMMMMNd........................cKMMMMMMWk,...........lXMMMM +MMMMMNd...........'dNMMMMMMXl......................:0MMMMMMWO;...........cKMMMMM +MMMMMMXl...........,kWMMMMMMKc....................,OWMMMMMM0:...........;0MMMMMM +MMMMMMMKc...........;OWMMMMMW0:..................,kWMMMMMMXc...........,OWMMMMMM +MMMMMMMM0;...........:KMMMMMMWKko:,..........';lx0WMMMMMMNo...........'xWMMMMMMM +MMMMMMMMWk,...........lXMMMMMMMMWWXOxl:,,;cdOKNWMMMMMMMMNx'...........dNMMMMMMMM +MMMMMMMMMWx'...........dNMMMMMMMMMMMMWNXXNWMMMMMMMMMMMMWk,...........lXMMMMMMMMM +MMMMMMMMMMNo............cx0XWMMMMMMMMMMMMMMMMMMMMMMWN0kl,...........cKMMMMMMMMMM +MMMMMMMMMMMXl..............,:ok0XWMMMMMMMMMMMMWNKkdc;..............;0WMMMMMMMMMM +MMMMMMMMMMMMK:..................,cokKNWMMWNKOdl;'.................,kWMMMMMMMMMMM +MMMMMMMMMMMMWO;......................;cool;'.....................'xNMMMMMMMMMMMM +MMMMMMMMMMMMMWk;................................................'dNMMMMMMMMMMMMM +MMMMMMMMMMMMMMWXOxl;'.......................................,cdkKWMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMWNKOdc;..............................,cok0NWMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMWNKkoc,....................,:ox0XWMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0ko:,..........':lx0XWMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWX0xl:,,;ldOKNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWNNXNWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM \ No newline at end of file diff --git a/src/tui/lib/rpclib.py b/src/tui/lib/rpclib.py new file mode 100644 index 000000000..a79fc73d4 --- /dev/null +++ b/src/tui/lib/rpclib.py @@ -0,0 +1,129 @@ +import http +from slickrpc import Proxy + + +# RPC connection +def rpc_connect(rpc_user, rpc_password, port): + try: + rpc_connection = Proxy("http://%s:%s@127.0.0.1:%d"%(rpc_user, rpc_password, port)) + except Exception: + raise Exception("Connection error! Probably no daemon on selected port.") + return rpc_connection + + +# Non CC calls +def getinfo(rpc_connection): + try: + getinfo = rpc_connection.getinfo() + except Exception: + raise Exception("Connection error!") + return getinfo + + +def sendrawtransaction(rpc_connection, hex): + tx_id = rpc_connection.sendrawtransaction(hex) + return tx_id + + +def gettransaction(rpc_connection, tx_id): + transaction_info = rpc_connection.gettransaction(tx_id) + return transaction_info + + +def getrawtransaction(rpc_connection, tx_id): + rawtransaction = rpc_connection.getrawtransaction(tx_id) + return rawtransaction + + +def getbalance(rpc_connection): + balance = rpc_connection.getbalance() + return balance + +# Token CC calls +def token_create(rpc_connection, name, supply, description): + token_hex = rpc_connection.tokencreate(name, supply, description) + return token_hex + + +def token_info(rpc_connection, token_id): + token_info = rpc_connection.tokeninfo(token_id) + return token_info + + +#TODO: have to add option with pubkey input +def token_balance(rpc_connection, token_id): + token_balance = rpc_connection.tokenbalance(token_id) + return token_balance + +def token_list(rpc_connection): + token_list = rpc_connection.tokenlist() + return token_list + + +def token_convert(rpc_connection, evalcode, token_id, pubkey, supply): + token_convert_hex = rpc_connection.tokenconvert(evalcode, token_id, pubkey, supply) + return token_convert_hex + +def get_rawmempool(rpc_connection): + mempool = rpc_connection.getrawmempool() + return mempool + +# Oracle CC calls +def oracles_create(rpc_connection, name, description, data_type): + oracles_hex = rpc_connection.oraclescreate(name, description, data_type) + return oracles_hex + + +def oracles_register(rpc_connection, oracle_id, data_fee): + oracles_register_hex = rpc_connection.oraclesregister(oracle_id, data_fee) + return oracles_register_hex + + +def oracles_subscribe(rpc_connection, oracle_id, publisher_id, data_fee): + oracles_subscribe_hex = rpc_connection.oraclessubscribe(oracle_id, publisher_id, data_fee) + return oracles_subscribe_hex + + +def oracles_info(rpc_connection, oracle_id): + oracles_info = rpc_connection.oraclesinfo(oracle_id) + return oracles_info + + +def oracles_data(rpc_connection, oracle_id, hex_string): + oracles_data = rpc_connection.oraclesdata(oracle_id, hex_string) + return oracles_data + + +def oracles_list(rpc_connection): + oracles_list = rpc_connection.oracleslist() + return oracles_list + + +def oracles_samples(rpc_connection, oracletxid, batonutxo, num): + oracles_sample = rpc_connection.oraclessamples(oracletxid, batonutxo, num) + return oracles_sample + + +# Gateways CC calls +# Arguments changing dynamically depends of M N, so supposed to wrap it this way +# token_id, oracle_id, coin_name, token_supply, M, N + pubkeys for each N +def gateways_bind(rpc_connection, *args): + gateways_bind_hex = rpc_connection.gatewaysbind(*args) + return gateways_bind_hex + + +def gateways_deposit(rpc_connection, gateway_id, height, coin_name,\ + coin_txid, claim_vout, deposit_hex, proof, dest_pub, amount): + gateways_deposit_hex = rpc_connection.gatewaysdeposit(gateway_id, height, coin_name,\ + coin_txid, claim_vout, deposit_hex, proof, dest_pub, amount) + return gateways_deposit_hex + + +def gateways_claim(rpc_connection, gateway_id, coin_name, deposit_txid, dest_pub, amount): + gateways_claim_hex = rpc_connection.gatewaysclaim(gateway_id, coin_name, deposit_txid, dest_pub, amount) + return gateways_claim_hex + + +def gateways_withdraw(rpc_connection, gateway_id, coin_name, withdraw_pub, amount): + gateways_withdraw_hex = rpc_connection.gatewayswithdraw(gateway_id, coin_name, withdraw_pub, amount) + return gateways_withdraw_hex diff --git a/src/tui/lib/tuilib.py b/src/tui/lib/tuilib.py new file mode 100755 index 000000000..9a2fed639 --- /dev/null +++ b/src/tui/lib/tuilib.py @@ -0,0 +1,1974 @@ +from lib import rpclib +import json +import time +import re +import sys +import pickle +import platform +import os +import subprocess +import random +import signal +from slickrpc import Proxy +from binascii import hexlify +from binascii import unhexlify +from functools import partial +from shutil import copy + + +operating_system = platform.system() +if operating_system != 'Win64' and operating_system != 'Windows': + import readline + + +def colorize(string, color): + + colors = { + 'blue': '\033[94m', + 'magenta': '\033[95m', + 'green': '\033[92m', + 'red': '\033[91m' + } + if color not in colors: + return string + else: + return colors[color] + string + '\033[0m' + + +def rpc_connection_tui(): + # TODO: possible to save multiply entries from successfull sessions and ask user to choose then + while True: + restore_choice = input("Do you want to use connection details from previous session? [y/n]: ") + if restore_choice == "y": + try: + with open("connection.json", "r") as file: + connection_json = json.load(file) + rpc_user = connection_json["rpc_user"] + rpc_password = connection_json["rpc_password"] + rpc_port = connection_json["rpc_port"] + rpc_connection = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + except FileNotFoundError: + print(colorize("You do not have cached connection details. Please select n for connection setup", "red")) + break + elif restore_choice == "n": + rpc_user = input("Input your rpc user: ") + rpc_password = input("Input your rpc password: ") + rpc_port = input("Input your rpc port: ") + connection_details = {"rpc_user": rpc_user, + "rpc_password": rpc_password, + "rpc_port": rpc_port} + connection_json = json.dumps(connection_details) + with open("connection.json", "w+") as file: + file.write(connection_json) + rpc_connection = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + break + else: + print(colorize("Please input y or n", "red")) + return rpc_connection + + +def def_credentials(chain): + rpcport =''; + operating_system = platform.system() + if operating_system == 'Darwin': + ac_dir = os.environ['HOME'] + '/Library/Application Support/Komodo' + elif operating_system == 'Linux': + ac_dir = os.environ['HOME'] + '/.komodo' + elif operating_system == 'Win64' or operating_system == 'Windows': + ac_dir = '%s/komodo/' % os.environ['APPDATA'] + if chain == 'KMD': + coin_config_file = str(ac_dir + '/komodo.conf') + else: + coin_config_file = str(ac_dir + '/' + chain + '/' + chain + '.conf') + with open(coin_config_file, 'r') as f: + for line in f: + l = line.rstrip() + if re.search('rpcuser', l): + rpcuser = l.replace('rpcuser=', '') + elif re.search('rpcpassword', l): + rpcpassword = l.replace('rpcpassword=', '') + elif re.search('rpcport', l): + rpcport = l.replace('rpcport=', '') + if len(rpcport) == 0: + if chain == 'KMD': + rpcport = 7771 + else: + print("rpcport not in conf file, exiting") + print("check "+coin_config_file) + exit(1) + + return(Proxy("http://%s:%s@127.0.0.1:%d"%(rpcuser, rpcpassword, int(rpcport)))) + + +def getinfo_tui(rpc_connection): + + info_raw = rpclib.getinfo(rpc_connection) + if isinstance(info_raw, dict): + for key in info_raw: + print("{}: {}".format(key, info_raw[key])) + input("Press [Enter] to continue...") + else: + print("Error!\n") + print(info_raw) + input("\nPress [Enter] to continue...") + + +def token_create_tui(rpc_connection): + + while True: + try: + name = input("Set your token name: ") + supply = input("Set your token supply: ") + description = input("Set your token description: ") + except KeyboardInterrupt: + break + else: + token_hex = rpclib.token_create(rpc_connection, name, supply, description) + if token_hex['result'] == "error": + print(colorize("\nSomething went wrong!\n", "pink")) + print(token_hex) + print("\n") + input("Press [Enter] to continue...") + break + else: + try: + token_txid = rpclib.sendrawtransaction(rpc_connection, + token_hex['hex']) + except KeyError: + print(token_txid) + print("Error") + input("Press [Enter] to continue...") + break + finally: + print(colorize("Token creation transaction broadcasted: " + token_txid, "green")) + file = open("tokens_list", "a") + file.writelines(token_txid + "\n") + file.close() + print(colorize("Entry added to tokens_list file!\n", "green")) + input("Press [Enter] to continue...") + break + + +def oracle_create_tui(rpc_connection): + + print(colorize("\nAvailiable data types:\n", "blue")) + oracles_data_types = ["Ihh -> height, blockhash, merkleroot\ns -> <256 char string\nS -> <65536 char string\nd -> <256 binary data\nD -> <65536 binary data", + "c -> 1 byte signed little endian number, C unsigned\nt -> 2 byte signed little endian number, T unsigned", + "i -> 4 byte signed little endian number, I unsigned\nl -> 8 byte signed little endian number, L unsigned", + "h -> 32 byte hash\n"] + for oracles_type in oracles_data_types: + print(str(oracles_type)) + while True: + try: + name = input("Set your oracle name: ") + description = input("Set your oracle description: ") + oracle_data_type = input("Set your oracle type (e.g. Ihh): ") + except KeyboardInterrupt: + break + else: + oracle_hex = rpclib.oracles_create(rpc_connection, name, description, oracle_data_type) + if oracle_hex['result'] == "error": + print(colorize("\nSomething went wrong!\n", "pink")) + print(oracle_hex) + print("\n") + input("Press [Enter] to continue...") + break + else: + try: + oracle_txid = rpclib.sendrawtransaction(rpc_connection, oracle_hex['hex']) + except KeyError: + print(oracle_txid) + print("Error") + input("Press [Enter] to continue...") + break + finally: + print(colorize("Oracle creation transaction broadcasted: " + oracle_txid, "green")) + file = open("oracles_list", "a") + file.writelines(oracle_txid + "\n") + file.close() + print(colorize("Entry added to oracles_list file!\n", "green")) + input("Press [Enter] to continue...") + break + + +def oracle_register_tui(rpc_connection): + #TODO: have an idea since blackjoker new RPC call + #grab all list and printout only or which owner match with node pubkey + try: + print(colorize("Oracles created from this instance by TUI: \n", "blue")) + with open("oracles_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + while True: + try: + oracle_id = input("Input txid of oracle you want to register to: ") + data_fee = input("Set publisher datafee (in satoshis): ") + except KeyboardInterrupt: + break + oracle_register_hex = rpclib.oracles_register(rpc_connection, oracle_id, data_fee) + if oracle_register_hex['result'] == "error": + print(colorize("\nSomething went wrong!\n", "pink")) + print(oracle_register_hex) + print("\n") + input("Press [Enter] to continue...") + break + else: + try: + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex['hex']) + except KeyError: + print(oracle_register_hex) + print("Error") + input("Press [Enter] to continue...") + break + else: + print(colorize("Oracle registration transaction broadcasted: " + oracle_register_txid, "green")) + input("Press [Enter] to continue...") + break + + +def oracle_subscription_utxogen(rpc_connection): + # TODO: have an idea since blackjoker new RPC call + # grab all list and printout only or which owner match with node pubkey + try: + print(colorize("Oracles created from this instance by TUI: \n", "blue")) + with open("oracles_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + while True: + try: + oracle_id = input("Input oracle ID you want to subscribe to: ") + #printout to fast copypaste publisher id + oracle_info = rpclib.oracles_info(rpc_connection, oracle_id) + publishers = 0 + print(colorize("\nPublishers registered for a selected oracle: \n", "blue")) + try: + for entry in oracle_info["registered"]: + publisher = entry["publisher"] + print(publisher + "\n") + publishers = publishers + 1 + print("Total publishers:{}".format(publishers)) + except (KeyError, ConnectionResetError): + print(colorize("Please re-check your input. Oracle txid seems not valid.", "red")) + pass + print(colorize('_' * 65, "blue")) + print("\n") + if publishers == 0: + print(colorize("This oracle have no publishers to subscribe.\n" + "Please register as an oracle publisher first and/or wait since registration transaciton mined!", "red")) + input("Press [Enter] to continue...") + break + publisher_id = input("Input oracle publisher id you want to subscribe to: ") + data_fee = input("Input subscription fee (in COINS!): ") + utxo_num = int(input("Input how many transactions you want to broadcast: ")) + except KeyboardInterrupt: + break + while utxo_num > 0: + while True: + oracle_subscription_hex = rpclib.oracles_subscribe(rpc_connection, oracle_id, publisher_id, data_fee) + oracle_subscription_txid = rpclib.sendrawtransaction(rpc_connection, oracle_subscription_hex['hex']) + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscription_txid in mempool: + break + else: + pass + print(colorize("Oracle subscription transaction broadcasted: " + oracle_subscription_txid, "green")) + utxo_num = utxo_num - 1 + input("Press [Enter] to continue...") + break + +def gateways_bind_tui(rpc_connection): + # main loop with keyboard interrupt handling + while True: + try: + while True: + try: + print(colorize("Tokens created from this instance by TUI: \n", "blue")) + with open("tokens_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + token_id = input("Input id of token you want to use in gw bind: ") + try: + token_name = rpclib.token_info(rpc_connection, token_id)["name"] + except KeyError: + print(colorize("Not valid tokenid. Please try again.", "red")) + input("Press [Enter] to continue...") + token_info = rpclib.token_info(rpc_connection, token_id) + print(colorize("\n{} token total supply: {}\n".format(token_id, token_info["supply"]), "blue")) + token_supply = input("Input supply for token binding: ") + try: + print(colorize("\nOracles created from this instance by TUI: \n", "blue")) + with open("oracles_list", "r") as file: + for oracle in file: + print(oracle) + print(colorize('_' * 65, "blue")) + print("\n") + except FileNotFoundError: + print("Seems like a no oracles created from this instance yet\n") + pass + oracle_id = input("Input id of oracle you want to use in gw bind: ") + try: + oracle_name = rpclib.oracles_info(rpc_connection, oracle_id)["name"] + except KeyError: + print(colorize("Not valid oracleid. Please try again.", "red")) + input("Press [Enter] to continue...") + while True: + coin_name = input("Input external coin ticker (binded oracle and token need to have same name!): ") + if token_name == oracle_name and token_name == coin_name: + break + else: + print(colorize("Token name, oracle name and external coin ticker should match!", "red")) + while True: + M = input("Input minimal amount of pubkeys needed for transaction confirmation (1 for non-multisig gw): ") + N = input("Input maximal amount of pubkeys needed for transaction confirmation (1 for non-multisig gw): ") + if (int(N) >= int(M)): + break + else: + print("Maximal amount of pubkeys should be more or equal than minimal. Please try again.") + pubkeys = [] + for i in range(int(N)): + pubkeys.append(input("Input pubkey {}: ".format(i+1))) + pubtype = input("Input pubtype of external coin: ") + p2shtype = input("Input p2shtype of external coin: ") + wiftype = input("Input wiftype of external coin: ") + args = [rpc_connection, token_id, oracle_id, coin_name, token_supply, M, N] + new_args = [str(pubtype), str(p2shtype), wiftype] + args = args + pubkeys + new_args + # broadcasting block + try: + gateways_bind_hex = rpclib.gateways_bind(*args) + except Exception as e: + print(e) + input("Press [Enter] to continue...") + break + try: + gateways_bind_txid = rpclib.sendrawtransaction(rpc_connection, gateways_bind_hex["hex"]) + except Exception as e: + print(e) + print(gateways_bind_hex) + input("Press [Enter] to continue...") + break + else: + print(colorize("Gateway bind transaction broadcasted: " + gateways_bind_txid, "green")) + file = open("gateways_list", "a") + file.writelines(gateways_bind_txid + "\n") + file.close() + print(colorize("Entry added to gateways_list file!\n", "green")) + input("Press [Enter] to continue...") + break + break + except KeyboardInterrupt: + break + +# temporary :trollface: custom connection function solution +# to have connection to KMD daemon and cache it in separate file + + +def rpc_kmd_connection_tui(): + while True: + restore_choice = input("Do you want to use KMD daemon connection details from previous session? [y/n]: ") + if restore_choice == "y": + try: + with open("connection_kmd.json", "r") as file: + connection_json = json.load(file) + rpc_user = connection_json["rpc_user"] + rpc_password = connection_json["rpc_password"] + rpc_port = connection_json["rpc_port"] + rpc_connection_kmd = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + try: + print(rpc_connection_kmd.getinfo()) + print(colorize("Successfully connected!\n", "green")) + input("Press [Enter] to continue...") + break + except Exception as e: + print(e) + print(colorize("NOT CONNECTED!\n", "red")) + input("Press [Enter] to continue...") + break + except FileNotFoundError: + print(colorize("You do not have cached KMD daemon connection details." + " Please select n for connection setup", "red")) + input("Press [Enter] to continue...") + elif restore_choice == "n": + rpc_user = input("Input your rpc user: ") + rpc_password = input("Input your rpc password: ") + rpc_port = input("Input your rpc port: ") + connection_details = {"rpc_user": rpc_user, + "rpc_password": rpc_password, + "rpc_port": rpc_port} + connection_json = json.dumps(connection_details) + with open("connection_kmd.json", "w+") as file: + file.write(connection_json) + rpc_connection_kmd = rpclib.rpc_connect(rpc_user, rpc_password, int(rpc_port)) + try: + print(rpc_connection_kmd.getinfo()) + print(colorize("Successfully connected!\n", "green")) + input("Press [Enter] to continue...") + break + except Exception as e: + print(e) + print(colorize("NOT CONNECTED!\n", "red")) + input("Press [Enter] to continue...") + break + else: + print(colorize("Please input y or n", "red")) + return rpc_connection_kmd + + +def z_sendmany_twoaddresses(rpc_connection, sendaddress, recepient1, amount1, recepient2, amount2): + str_sending_block = "[{{\"address\":\"{}\",\"amount\":{}}},{{\"address\":\"{}\",\"amount\":{}}}]".format(recepient1, amount1, recepient2, amount2) + sending_block = json.loads(str_sending_block) + operation_id = rpc_connection.z_sendmany(sendaddress,sending_block) + return operation_id + + +def operationstatus_to_txid(rpc_connection, zstatus): + str_sending_block = "[\"{}\"]".format(zstatus) + sending_block = json.loads(str_sending_block) + operation_json = rpc_connection.z_getoperationstatus(sending_block) + operation_dump = json.dumps(operation_json) + operation_dict = json.loads(operation_dump)[0] + txid = operation_dict['result']['txid'] + return txid + + +def gateways_send_kmd(rpc_connection): + # TODO: have to handle CTRL+C on text input + print(colorize("Please be carefull when input wallet addresses and amounts since all transactions doing in real KMD!", "pink")) + print("Your addresses with balances: ") + list_address_groupings = rpc_connection.listaddressgroupings() + for address in list_address_groupings: + print(str(address) + "\n") + sendaddress = input("Input address from which you transfer KMD: ") + recepient1 = input("Input address which belongs to pubkey which will receive tokens: ") + amount1 = 0.0001 + recepient2 = input("Input gateway deposit address: ") + file = open("deposits_list", "a") + #have to show here deposit addresses for gateways created by user + amount2 = input("Input how many KMD you want to deposit on this gateway: ") + operation = z_sendmany_twoaddresses(rpc_connection, sendaddress, recepient1, amount1, recepient2, amount2) + print("Operation proceed! " + str(operation) + " Let's wait 2 seconds to get txid") + # trying to avoid pending status of operation + time.sleep(2) + txid = operationstatus_to_txid(rpc_connection, operation) + file.writelines(txid + "\n") + file.close() + print(colorize("KMD Transaction ID: " + str(txid) + " Entry added to deposits_list file", "green")) + input("Press [Enter] to continue...") + + +def gateways_deposit_tui(rpc_connection_assetchain, rpc_connection_komodo): + while True: + bind_txid = input("Input your gateway bind txid: ") + coin_name = input("Input your external coin ticker (e.g. KMD): ") + coin_txid = input("Input your deposit txid: ") + dest_pub = input("Input pubkey which claim deposit: ") + amount = input("Input amount of your deposit: ") + height = rpc_connection_komodo.getrawtransaction(coin_txid, 1)["height"] + deposit_hex = rpc_connection_komodo.getrawtransaction(coin_txid, 1)["hex"] + claim_vout = "0" + proof_sending_block = "[\"{}\"]".format(coin_txid) + proof = rpc_connection_komodo.gettxoutproof(json.loads(proof_sending_block)) + deposit_hex = rpclib.gateways_deposit(rpc_connection_assetchain, bind_txid, str(height), coin_name, \ + coin_txid, claim_vout, deposit_hex, proof, dest_pub, amount) + print(deposit_hex) + deposit_txid = rpclib.sendrawtransaction(rpc_connection_assetchain, deposit_hex["hex"]) + print("Done! Gateways deposit txid is: " + deposit_txid + " Please not forget to claim your deposit!") + input("Press [Enter] to continue...") + break + + +def gateways_claim_tui(rpc_connection): + while True: + bind_txid = input("Input your gateway bind txid: ") + coin_name = input("Input your external coin ticker (e.g. KMD): ") + deposit_txid = input("Input your gatewaysdeposit txid: ") + dest_pub = input("Input pubkey which claim deposit: ") + amount = input("Input amount of your deposit: ") + claim_hex = rpclib.gateways_claim(rpc_connection, bind_txid, coin_name, deposit_txid, dest_pub, amount) + try: + claim_txid = rpclib.sendrawtransaction(rpc_connection, claim_hex["hex"]) + except Exception as e: + print(e) + print(claim_hex) + input("Press [Enter] to continue...") + break + else: + print("Succesfully claimed! Claim transaction id: " + claim_txid) + input("Press [Enter] to continue...") + break + + +def gateways_withdrawal_tui(rpc_connection): + while True: + bind_txid = input("Input your gateway bind txid: ") + coin_name = input("Input your external coin ticker (e.g. KMD): ") + withdraw_pub = input("Input pubkey to which you want to withdraw: ") + amount = input("Input amount of withdrawal: ") + withdraw_hex = rpclib.gateways_withdraw(rpc_connection, bind_txid, coin_name, withdraw_pub, amount) + withdraw_txid = rpclib.sendrawtransaction(rpc_connection, withdraw_hex["hex"]) + print(withdraw_txid) + input("Press [Enter] to continue...") + break + + +def print_mempool(rpc_connection): + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + tx_counter = 0 + print(colorize("Transactions in mempool: \n", "magenta")) + for transaction in mempool: + print(transaction + "\n") + tx_counter = tx_counter + 1 + print("Total: " + str(tx_counter) + " transactions\n") + print("R + Enter to refresh list. E + Enter to exit menu." + "\n") + is_refresh = input("Choose your destiny: ") + if is_refresh == "R": + print("\n") + pass + elif is_refresh == "E": + print("\n") + break + else: + print("\nPlease choose R or E\n") + + +def print_tokens_list(rpc_connection): + # TODO: have to print it with tokeninfo to have sense + pass + + +def print_tokens_balances(rpc_connection): + # TODO: checking tokenbalance for each token from tokenlist and reflect non zero ones + pass + + +def hexdump(filename, chunk_size=1<<15): + data = "" + #add_spaces = partial(re.compile(b'(..)').sub, br'\1 ') + #write = getattr(sys.stdout, 'buffer', sys.stdout).write + with open(filename, 'rb') as file: + for chunk in iter(partial(file.read, chunk_size), b''): + data += str(hexlify(chunk).decode()) + return data + + +def convert_file_oracle_d(rpc_connection): + while True: + path = input("Input path to file you want to upload to oracle: ") + try: + hex_data = (hexdump(path, 1))[2:] + except Exception as e: + print(e) + print("Seems something goes wrong (I guess you've specified wrong path)!") + input("Press [Enter] to continue...") + break + else: + length = round(len(hex_data) / 2) + if length > 256: + print("Length: " + str(length) + " bytes") + print("File is too big for this app") + input("Press [Enter] to continue...") + break + else: + hex_length = format(length, '#04x')[2:] + data_for_oracle = str(hex_length) + hex_data + print("File hex representation: \n") + print(data_for_oracle + "\n") + print("Length: " + str(length) + " bytes") + print("File converted!") + new_oracle_hex = rpclib.oracles_create(rpc_connection, "tonyconvert", path, "d") + new_oracle_txid = rpclib.sendrawtransaction(rpc_connection, new_oracle_hex["hex"]) + time.sleep(0.5) + oracle_register_hex = rpclib.oracles_register(rpc_connection, new_oracle_txid, "10000") + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex["hex"]) + time.sleep(0.5) + oracle_subscribe_hex = rpclib.oracles_subscribe(rpc_connection, new_oracle_txid, rpclib.getinfo(rpc_connection)["pubkey"], "0.001") + oracle_subscribe_txid = rpclib.sendrawtransaction(rpc_connection, oracle_subscribe_hex["hex"]) + time.sleep(0.5) + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscribe_txid in mempool: + print("Waiting for oracle subscribtion tx to be mined" + "\n") + time.sleep(6) + pass + else: + break + oracles_data_hex = rpclib.oracles_data(rpc_connection, new_oracle_txid, data_for_oracle) + try: + oracle_data_txid = rpclib.sendrawtransaction(rpc_connection, oracles_data_hex["hex"]) + except Exception as e: + print(oracles_data_hex) + print(e) + print("Oracle created: " + str(new_oracle_txid)) + print("Data published: " + str(oracle_data_txid)) + input("Press [Enter] to continue...") + break + + +def convert_file_oracle_D(rpc_connection): + while True: + path = input("Input path to file you want to upload to oracle: ") + try: + hex_data = (hexdump(path, 1)) + except Exception as e: + print(e) + print("Seems something goes wrong (I guess you've specified wrong path)!") + input("Press [Enter] to continue...") + break + else: + length = round(len(hex_data) / 2) + # if length > 800000: + # print("Too big file size to upload for this version of program. Maximum size is 800KB.") + # input("Press [Enter] to continue...") + # break + if length > 8000: + # if file is more than 8000 bytes - slicing it to <= 8000 bytes chunks (16000 symbols = 8000 bytes) + data = [hex_data[i:i + 16000] for i in range(0, len(hex_data), 16000)] + chunks_amount = len(data) + # TODO: have to create oracle but subscribe this time chunks amount times to send whole file in same block + # TODO: 2 - on some point file will not fit block - have to find this point + # TODO: 3 way how I want to implement it first will keep whole file in RAM - have to implement some way to stream chunks to oracle before whole file readed + # TODO: have to "optimise" registration fee + # Maybe just check size first by something like a du ? + print("Length: " + str(length) + " bytes.\n Chunks amount: " + str(chunks_amount)) + new_oracle_hex = rpclib.oracles_create(rpc_connection, "tonyconvert_" + str(chunks_amount), path, "D") + new_oracle_txid = rpclib.sendrawtransaction(rpc_connection, new_oracle_hex["hex"]) + time.sleep(0.5) + oracle_register_hex = rpclib.oracles_register(rpc_connection, new_oracle_txid, "10000") + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex["hex"]) + # subscribe chunks_amount + 1 times, but lets limit our broadcasting 100 tx per block (800KB/block) + if chunks_amount > 100: + utxo_num = 101 + else: + utxo_num = chunks_amount + while utxo_num > 0: + while True: + oracle_subscription_hex = rpclib.oracles_subscribe(rpc_connection, new_oracle_txid, rpclib.getinfo(rpc_connection)["pubkey"], "0.001") + oracle_subscription_txid = rpclib.sendrawtransaction(rpc_connection, + oracle_subscription_hex['hex']) + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscription_txid in mempool: + break + else: + pass + print(colorize("Oracle subscription transaction broadcasted: " + oracle_subscription_txid, "green")) + utxo_num = utxo_num - 1 + # waiting for last broadcasted subscribtion transaction to be mined to be sure that money are on oracle balance + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscription_txid in mempool: + print("Waiting for oracle subscribtion tx to be mined" + "\n") + time.sleep(6) + pass + else: + break + print("Oracle preparation is finished. Oracle txid: " + new_oracle_txid) + # can publish data now + counter = 0 + for chunk in data: + hex_length_bigendian = format(round(len(chunk) / 2), '#06x')[2:] + # swap to get little endian length + a = hex_length_bigendian[2:] + b = hex_length_bigendian[:2] + hex_length = a + b + data_for_oracle = str(hex_length) + chunk + counter = counter + 1 + # print("Chunk number: " + str(counter) + "\n") + # print(data_for_oracle) + try: + oracles_data_hex = rpclib.oracles_data(rpc_connection, new_oracle_txid, data_for_oracle) + except Exception as e: + print(data_for_oracle) + print(e) + input("Press [Enter] to continue...") + break + # on broadcasting ensuring that previous one reached mempool before blast next one + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + oracle_data_txid = rpclib.sendrawtransaction(rpc_connection, oracles_data_hex["hex"]) + #time.sleep(0.1) + if oracle_data_txid in mempool: + break + else: + pass + # blasting not more than 100 at once (so maximum capacity per block can be changed here) + # but keep in mind that registration UTXOs amount needs to be changed too ! + if counter % 100 == 0 and chunks_amount > 100: + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_data_txid in mempool: + print("Waiting for previous data chunks to be mined before send new ones" + "\n") + print("Sent " + str(counter) + " chunks from " + str(chunks_amount)) + time.sleep(6) + pass + else: + break + + print("Last baton: " + oracle_data_txid) + input("Press [Enter] to continue...") + break + # if file suits single oraclesdata just broadcasting it straight without any slicing + else: + hex_length_bigendian = format(length, '#06x')[2:] + # swap to get little endian length + a = hex_length_bigendian[2:] + b = hex_length_bigendian[:2] + hex_length = a + b + data_for_oracle = str(hex_length) + hex_data + print("File hex representation: \n") + print(data_for_oracle + "\n") + print("Length: " + str(length) + " bytes") + print("File converted!") + new_oracle_hex = rpclib.oracles_create(rpc_connection, "tonyconvert_" + "1", path, "D") + new_oracle_txid = rpclib.sendrawtransaction(rpc_connection, new_oracle_hex["hex"]) + time.sleep(0.5) + oracle_register_hex = rpclib.oracles_register(rpc_connection, new_oracle_txid, "10000") + oracle_register_txid = rpclib.sendrawtransaction(rpc_connection, oracle_register_hex["hex"]) + time.sleep(0.5) + oracle_subscribe_hex = rpclib.oracles_subscribe(rpc_connection, new_oracle_txid, rpclib.getinfo(rpc_connection)["pubkey"], "0.001") + oracle_subscribe_txid = rpclib.sendrawtransaction(rpc_connection, oracle_subscribe_hex["hex"]) + time.sleep(0.5) + while True: + mempool = rpclib.get_rawmempool(rpc_connection) + if oracle_subscribe_txid in mempool: + print("Waiting for oracle subscribtion tx to be mined" + "\n") + time.sleep(6) + pass + else: + break + oracles_data_hex = rpclib.oracles_data(rpc_connection, new_oracle_txid, data_for_oracle) + try: + oracle_data_txid = rpclib.sendrawtransaction(rpc_connection, oracles_data_hex["hex"]) + except Exception as e: + print(oracles_data_hex) + print(e) + input("Press [Enter] to continue...") + break + else: + print("Oracle created: " + str(new_oracle_txid)) + print("Data published: " + str(oracle_data_txid)) + input("Press [Enter] to continue...") + break + + +def get_files_list(rpc_connection): + + start_time = time.time() + oracles_list = rpclib.oracles_list(rpc_connection) + files_list = [] + for oracle_txid in oracles_list: + oraclesinfo_result = rpclib.oracles_info(rpc_connection, oracle_txid) + description = oraclesinfo_result['description'] + name = oraclesinfo_result['name'] + if name[0:12] == 'tonyconvert_': + new_file = '[' + name + ': ' + description + ']: ' + oracle_txid + files_list.append(new_file) + print("--- %s seconds ---" % (time.time() - start_time)) + return files_list + + +def display_files_list(rpc_connection): + print("Scanning oracles. Please wait...") + list_to_display = get_files_list(rpc_connection) + while True: + for file in list_to_display: + print(file + "\n") + input("Press [Enter] to continue...") + break + + +def files_downloader(rpc_connection): + while True: + display_files_list(rpc_connection) + print("\n") + oracle_id = input("Input oracle ID you want to download file from: ") + output_path = input("Input output path for downloaded file (name included) e.g. /home/test.txt: ") + oracle_info = rpclib.oracles_info(rpc_connection, oracle_id) + name = oracle_info['name'] + latest_baton_txid = oracle_info['registered'][0]['batontxid'] + if name[0:12] == 'tonyconvert_': + # downloading process here + chunks_amount = int(name[12:]) + data = rpclib.oracles_samples(rpc_connection, oracle_id, latest_baton_txid, str(chunks_amount))["samples"] + for chunk in reversed(data): + with open(output_path, 'ab+') as file: + file.write(unhexlify(chunk[0])) + print("I hope that file saved to " + output_path + "\n") + input("Press [Enter] to continue...") + break + + else: + print("I cant recognize file inside this oracle. I'm very sorry, boss.") + input("Press [Enter] to continue...") + break + + +def marmara_receive_tui(rpc_connection): + while True: + issuer_pubkey = input("Input pubkey of person who do you want to receive MARMARA from: ") + issuance_sum = input("Input amount of MARMARA you want to receive: ") + blocks_valid = input("Input amount of blocks for cheque matures: ") + try: + marmara_receive_txinfo = rpc_connection.marmarareceive(issuer_pubkey, issuance_sum, "MARMARA", blocks_valid) + marmara_receive_txid = rpc_connection.sendrawtransaction(marmara_receive_txinfo["hex"]) + print("Marmara receive txid broadcasted: " + marmara_receive_txid + "\n") + print(json.dumps(marmara_receive_txinfo, indent=4, sort_keys=True) + "\n") + with open("receive_txids.txt", 'a+') as file: + file.write(marmara_receive_txid + "\n") + file.write(json.dumps(marmara_receive_txinfo, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to receive_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_receive_txinfo) + print(e) + print("Something went wrong. Please check your input") + + +def marmara_issue_tui(rpc_connection): + while True: + receiver_pubkey = input("Input pubkey of person who do you want to issue MARMARA: ") + issuance_sum = input("Input amount of MARMARA you want to issue: ") + maturing_block = input("Input number of block on which issuance mature: ") + approval_txid = input("Input receiving request transaction id: ") + try: + marmara_issue_txinfo = rpc_connection.marmaraissue(receiver_pubkey, issuance_sum, "MARMARA", maturing_block, approval_txid) + marmara_issue_txid = rpc_connection.sendrawtransaction(marmara_issue_txinfo["hex"]) + print("Marmara issuance txid broadcasted: " + marmara_issue_txid + "\n") + print(json.dumps(marmara_issue_txinfo, indent=4, sort_keys=True) + "\n") + with open("issue_txids.txt", "a+") as file: + file.write(marmara_issue_txid + "\n") + file.write(json.dumps(marmara_issue_txinfo, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to issue_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_issue_txinfo) + print(e) + print("Something went wrong. Please check your input") + + +def marmara_creditloop_tui(rpc_connection): + while True: + loop_txid = input("Input transaction ID of credit loop you want to get info about: ") + try: + marmara_creditloop_info = rpc_connection.marmaracreditloop(loop_txid) + print(json.dumps(marmara_creditloop_info, indent=4, sort_keys=True) + "\n") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_creditloop_info) + print(e) + print("Something went wrong. Please check your input") + + +def marmara_settlement_tui(rpc_connection): + while True: + loop_txid = input("Input transaction ID of credit loop to make settlement: ") + try: + marmara_settlement_info = rpc_connection.marmarasettlement(loop_txid) + marmara_settlement_txid = rpc_connection.sendrawtransaction(marmara_settlement_info["hex"]) + print("Loop " + loop_txid + " succesfully settled!\nSettlement txid: " + marmara_settlement_txid) + with open("settlement_txids.txt", "a+") as file: + file.write(marmara_settlement_txid + "\n") + file.write(json.dumps(marmara_settlement_info, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to settlement_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_settlement_info) + print(e) + print("Something went wrong. Please check your input") + input("Press [Enter] to continue...") + break + + +def marmara_lock_tui(rpc_connection): + while True: + amount = input("Input amount of coins you want to lock for settlement and staking: ") + unlock_height = input("Input height on which coins should be unlocked: ") + try: + marmara_lock_info = rpc_connection.marmaralock(amount, unlock_height) + marmara_lock_txid = rpc_connection.sendrawtransaction(marmara_lock_info["hex"]) + with open("lock_txids.txt", "a+") as file: + file.write(marmara_lock_txid + "\n") + file.write(json.dumps(marmara_lock_info, indent=4, sort_keys=True) + "\n") + print("Transaction id is saved to lock_txids.txt file.") + input("Press [Enter] to continue...") + break + except Exception as e: + print(e) + print("Something went wrong. Please check your input") + input("Press [Enter] to continue...") + break + + +def marmara_info_tui(rpc_connection): + while True: + firstheight = input("Input first height (default 0): ") + if not firstheight: + firstheight = "0" + lastheight = input("Input last height (default current (0) ): ") + if not lastheight: + lastheight = "0" + minamount = input("Input min amount (default 0): ") + if not minamount: + minamount = "0" + maxamount = input("Input max amount (default 0): ") + if not maxamount: + maxamount = "0" + issuerpk = input("Optional. Input issuer public key: ") + try: + if issuerpk: + marmara_info = rpc_connection.marmarainfo(firstheight, lastheight, minamount, maxamount, "MARMARA", issuerpk) + else: + marmara_info = rpc_connection.marmarainfo(firstheight, lastheight, minamount, maxamount) + print(json.dumps(marmara_info, indent=4, sort_keys=True) + "\n") + input("Press [Enter] to continue...") + break + except Exception as e: + print(marmara_info) + print(e) + print("Something went wrong. Please check your input") + input("Press [Enter] to continue...") + break + + +def rogue_game_info(rpc_connection, game_txid): + game_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + game_info = rpc_connection.cclib("gameinfo", "17", game_info_arg) + return game_info + + +def rogue_game_register(rpc_connection, game_txid, player_txid = False): + if player_txid: + registration_info_arg = '"' + "[%22" + game_txid + "%22,%22" + player_txid + "%22]" + '"' + else: + registration_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + registration_info = rpc_connection.cclib("register", "17", registration_info_arg) + return registration_info + + +def rogue_pending(rpc_connection): + rogue_pending_list = rpc_connection.cclib("pending", "17") + return rogue_pending_list + + +def rogue_bailout(rpc_connection, game_txid): + bailout_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + bailout_info = rpc_connection.cclib("bailout", "17", bailout_info_arg) + return bailout_info + + +def rogue_highlander(rpc_connection, game_txid): + highlander_info_arg = '"' + "[%22" + game_txid + "%22]" + '"' + highlander_info = rpc_connection.cclib("highlander", "17", highlander_info_arg) + return highlander_info + + +def rogue_players_list(rpc_connection): + rogue_players_list = rpc_connection.cclib("players", "17") + return rogue_players_list + + +def rogue_player_info(rpc_connection, playertxid): + player_info_arg = '"' + "[%22" + playertxid + "%22]" + '"' + player_info = rpc_connection.cclib("playerinfo", "17", player_info_arg) + return player_info + + +def rogue_extract(rpc_connection, game_txid, pubkey): + extract_info_arg = '"' + "[%22" + game_txid + "%22,%22" + pubkey + "%22]" + '"' + extract_info = rpc_connection.cclib("extract", "17", extract_info_arg) + return extract_info + + +def rogue_keystrokes(rpc_connection, game_txid, keystroke): + rogue_keystrokes_arg = '"' + "[%22" + game_txid + "%22,%22" + keystroke + "%22]" + '"' + keystroke_info = rpc_connection.cclib("keystrokes", "17", rogue_keystrokes_arg) + return keystroke_info + + +def print_multiplayer_games_list(rpc_connection): + while True: + pending_list = rogue_pending(rpc_connection) + multiplayer_pending_list = [] + for game in pending_list["pending"]: + if rogue_game_info(rpc_connection, game)["maxplayers"] > 1: + multiplayer_pending_list.append(game) + print("Multiplayer games availiable to join: \n") + for active_multiplayer_game in multiplayer_pending_list: + game_info = rogue_game_info(rpc_connection, active_multiplayer_game) + print(colorize("\n================================\n", "green")) + print("Game txid: " + game_info["gametxid"]) + print("Game buyin: " + str(game_info["buyin"])) + print("Game height: " + str(game_info["gameheight"])) + print("Start height: " + str(game_info["start"])) + print("Alive players: " + str(game_info["alive"])) + print("Registered players: " + str(game_info["numplayers"])) + print("Max players: " + str(game_info["maxplayers"])) + print(colorize("\n***\n", "blue")) + print("Players in game:") + for player in game_info["players"]: + print("Slot: " + str(player["slot"])) + if "baton" in player.keys(): + print("Baton: " + str(player["baton"])) + if "tokenid" in player.keys(): + print("Tokenid: " + str(player["tokenid"])) + print("Is mine?: " + str(player["ismine"])) + print(colorize("\nR + Enter - refresh list.\nE + Enter - to the game choice.\nCTRL + C - back to main menu", "blue")) + is_refresh = input("Choose your destiny: ") + if is_refresh == "R": + print("\n") + pass + elif is_refresh == "E": + print("\n") + break + else: + print("\nPlease choose R or E\n") + + +def rogue_newgame_singleplayer(rpc_connection, is_game_a_rogue=True): + try: + if is_game_a_rogue: + new_game_txid = rpc_connection.cclib("newgame", "17", "[1]")["txid"] + print("New singleplayer training game succesfully created. txid: " + new_game_txid) + while True: + mempool = rpc_connection.getrawmempool() + if new_game_txid in mempool: + print(colorize("Waiting for game transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Game transaction is mined", "green")) + break + else: + pending_games = rpc_connection.cclib("pending", "17")["pending"] + new_game_txid = random.choice(pending_games) + if is_game_a_rogue: + players_list = rogue_players_list(rpc_connection) + if len(players_list["playerdata"]) > 0: + print_players_list(rpc_connection) + while True: + is_choice_needed = input("Do you want to choose a player for this game? [y/n] ") + if is_choice_needed == "y": + player_txid = input("Please input player txid: ") + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid, player_txid)["txid"] + break + elif is_choice_needed == "n": + set_warriors_name(rpc_connection) + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] + break + else: + print("Please choose y or n !") + else: + print("No players available to select") + input("Press [Enter] to continue...") + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] + else: + newgame_regisration_txid = rogue_game_register(rpc_connection, new_game_txid)["txid"] + while True: + mempool = rpc_connection.getrawmempool() + if newgame_regisration_txid in mempool: + print(colorize("Waiting for registration transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Registration transaction is mined", "green")) + break + game_info = rogue_game_info(rpc_connection, new_game_txid) + start_time = time.time() + while True: + if is_game_a_rogue: + subprocess.call(["../cc/rogue/rogue", str(game_info["seed"]), str(game_info["gametxid"])]) + else: + subprocess.call(["../cc/games/tetris", str(game_info["seed"]), str(game_info["gametxid"])]) + time_elapsed = time.time() - start_time + if time_elapsed > 1: + break + else: + print("Game less than 1 second. Trying to start again") + time.sleep(1) + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout", "blue")) + time.sleep(5) + else: + break + #print("\nKeystrokes of this game:\n") + #time.sleep(0.5) + while True: + keystrokes_rpc_responses = find_game_keystrokes_in_log(new_game_txid)[1::2] + if len(keystrokes_rpc_responses) < 1: + print("No keystrokes broadcasted yet. Let's wait 5 seconds") + time.sleep(5) + else: + break + #print(keystrokes_rpc_responses) + for keystroke in keystrokes_rpc_responses: + json_keystroke = json.loads(keystroke)["result"] + if "status" in json_keystroke.keys() and json_keystroke["status"] == "error": + while True: + print("Trying to re-brodcast keystroke") + keystroke_rebroadcast = rogue_keystrokes(rpc_connection, json_keystroke["gametxid"], json_keystroke["keystrokes"]) + if "txid" in keystroke_rebroadcast.keys(): + print("Keystroke broadcasted! txid: " + keystroke_rebroadcast["txid"]) + break + else: + print("Let's try again in 5 seconds") + time.sleep(5) + # waiting for last keystroke confirmation here + last_keystroke_json = json.loads(keystrokes_rpc_responses[-1]) + while True: + while True: + try: + rpc_connection.sendrawtransaction(last_keystroke_json["result"]["hex"]) + except Exception as e: + pass + try: + confirmations_amount = rpc_connection.getrawtransaction(last_keystroke_json["result"]["txid"], 1)["confirmations"] + break + except Exception as e: + print(e) + print("Let's wait a little bit more") + time.sleep(5) + pass + if confirmations_amount < 1: + print("Last keystroke not confirmed yet! Let's wait a little") + time.sleep(10) + else: + print("Last keystroke confirmed!") + break + while True: + print("\nExtraction info:\n") + extraction_info = rogue_extract(rpc_connection, new_game_txid, rpc_connection.getinfo()["pubkey"]) + if extraction_info["status"] == "error": + print(colorize("Your warrior died or no any information about game was saved on blockchain", "red")) + print("If warrior was alive - try to wait a little (choose n to wait for a next block). If he is dead - you can bailout now (choose y).") + else: + print("Current game state:") + print("Game txid: " + extraction_info["gametxid"]) + print("Information about game saved on chain: " + extraction_info["extracted"]) + print("\n") + is_bailout_needed = input("Do you want to make bailout now [y] or wait for one more block [n]? [y/n]: ") + if is_bailout_needed == "y": + bailout_info = rogue_bailout(rpc_connection, new_game_txid) + if is_game_a_rogue: + while True: + try: + confirmations_amount = rpc_connection.getrawtransaction(bailout_info["txid"], 1)["confirmations"] + break + except Exception as e: + print(e) + print("Bailout not on blockchain yet. Let's wait a little bit more") + time.sleep(20) + pass + break + elif is_bailout_needed == "n": + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout", "blue")) + time.sleep(5) + else: + break + else: + print("Please choose y or n !") + print(bailout_info) + print("\nGame is finished!\n") + bailout_txid = bailout_info["txid"] + input("Press [Enter] to continue...") + except Exception as e: + print("Something went wrong.") + print(e) + input("Press [Enter] to continue...") + + +def play_multiplayer_game(rpc_connection): + # printing list of user active multiplayer games + active_games_list = rpc_connection.cclib("games", "17")["games"] + active_multiplayer_games_list = [] + for game in active_games_list: + gameinfo = rogue_game_info(rpc_connection, game) + if gameinfo["maxplayers"] > 1: + active_multiplayer_games_list.append(gameinfo) + games_counter = 0 + for active_multiplayer_game in active_multiplayer_games_list: + games_counter = games_counter + 1 + is_ready_to_start = False + try: + active_multiplayer_game["seed"] + is_ready_to_start = True + except Exception as e: + pass + print(colorize("\n================================\n", "green")) + print("Game txid: " + active_multiplayer_game["gametxid"]) + print("Game buyin: " + str(active_multiplayer_game["buyin"])) + if is_ready_to_start: + print(colorize("Ready for start!", "green")) + else: + print(colorize("Not ready for start yet, wait until start height!", "red")) + print("Game height: " + str(active_multiplayer_game["gameheight"])) + print("Start height: " + str(active_multiplayer_game["start"])) + print("Alive players: " + str(active_multiplayer_game["alive"])) + print("Registered players: " + str(active_multiplayer_game["numplayers"])) + print("Max players: " + str(active_multiplayer_game["maxplayers"])) + print(colorize("\n***\n", "blue")) + print("Players in game:") + for player in active_multiplayer_game["players"]: + print("Slot: " + str(player["slot"])) + print("Baton: " + str(player["baton"])) + print("Tokenid: " + str(player["tokenid"])) + print("Is mine?: " + str(player["ismine"])) + # asking user if he want to start any of them + while True: + start_game = input("\nDo you want to start any of your pendning multiplayer games?[y/n]: ") + if start_game == "y": + new_game_txid = input("Input txid of game which you want to start: ") + game_info = rogue_game_info(rpc_connection, new_game_txid) + try: + start_time = time.time() + while True: + subprocess.call(["cc/rogue/rogue", str(game_info["seed"]), str(game_info["gametxid"])]) + time_elapsed = time.time() - start_time + if time_elapsed > 1: + break + else: + print("Game less than 1 second. Trying to start again") + time.sleep(1) + except Exception as e: + print("Maybe game isn't ready for start yet or your input was not correct, sorry.") + input("Press [Enter] to continue...") + break + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout or highlander", "blue")) + time.sleep(5) + else: + break + while True: + keystrokes_rpc_responses = find_game_keystrokes_in_log(new_game_txid)[1::2] + if len(keystrokes_rpc_responses) < 1: + print("No keystrokes broadcasted yet. Let's wait 5 seconds") + time.sleep(5) + else: + break + for keystroke in keystrokes_rpc_responses: + json_keystroke = json.loads(keystroke)["result"] + if "status" in json_keystroke.keys() and json_keystroke["status"] == "error": + while True: + print("Trying to re-brodcast keystroke") + keystroke_rebroadcast = rogue_keystrokes(rpc_connection, json_keystroke["gametxid"], + json_keystroke["keystrokes"]) + if "txid" in keystroke_rebroadcast.keys(): + print("Keystroke broadcasted! txid: " + keystroke_rebroadcast["txid"]) + break + else: + print("Let's try again in 5 seconds") + time.sleep(5) + last_keystroke_json = json.loads(keystrokes_rpc_responses[-1]) + while True: + while True: + try: + confirmations_amount = rpc_connection.getrawtransaction(last_keystroke_json["result"]["txid"], 1)["confirmations"] + break + except Exception as e: + print(e) + print("Let's wait a little bit more") + rpc_connection.sendrawtransaction(last_keystroke_json["result"]["hex"]) + time.sleep(5) + pass + if confirmations_amount < 2: + print("Last keystroke not confirmed yet! Let's wait a little") + time.sleep(10) + else: + print("Last keystroke confirmed!") + break + while True: + print("\nExtraction info:\n") + extraction_info = rogue_extract(rpc_connection, new_game_txid, rpc_connection.getinfo()["pubkey"]) + if extraction_info["status"] == "error": + print(colorize("Your warrior died or no any information about game was saved on blockchain", "red")) + print("If warrior was alive - try to wait a little (choose n to wait for a next block). If he is dead - you can bailout now (choose y).") + else: + print("Current game state:") + print("Game txid: " + extraction_info["gametxid"]) + print("Information about game saved on chain: " + extraction_info["extracted"]) + print("\n") + is_bailout_needed = input( + "Do you want to make bailout now [y] or wait for one more block [n]? [y/n]: ") + if is_bailout_needed == "y": + if game_info["alive"] > 1: + bailout_info = rogue_bailout(rpc_connection, new_game_txid) + try: + bailout_txid = bailout_info["txid"] + print(bailout_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + except Exception: + highlander_info = rogue_highlander(rpc_connection, new_game_txid) + highlander_info = highlander_info["txid"] + print(highlander_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + else: + highlander_info = rogue_highlander(rpc_connection, new_game_txid) + if 'error' in highlander_info.keys() and highlander_info["error"] == 'numplayers != maxplayers': + bailout_info = rogue_bailout(rpc_connection, new_game_txid) + print(bailout_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + else: + print(highlander_info) + print("\nGame is finished!\n") + input("Press [Enter] to continue...") + break + elif is_bailout_needed == "n": + game_end_height = int(rpc_connection.getinfo()["blocks"]) + while True: + current_height = int(rpc_connection.getinfo()["blocks"]) + height_difference = current_height - game_end_height + if height_difference == 0: + print(current_height) + print(game_end_height) + print(colorize("Waiting for next block before bailout", "blue")) + time.sleep(5) + else: + break + break + break + if start_game == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def rogue_newgame_multiplayer(rpc_connection): + while True: + max_players = input("Input game max. players (>1): ") + if int(max_players) > 1: + break + else: + print("Please re-check your input") + input("Press [Enter] to continue...") + while True: + buyin = input("Input game buyin (>0.001): ") + if float(buyin) > 0.001: + break + else: + print("Please re-check your input") + input("Press [Enter] to continue...") + try: + new_game_txid = rpc_connection.cclib("newgame", "17", '"[' + max_players + "," + buyin + ']"')["txid"] + print(colorize("New multiplayer game succesfully created. txid: " + new_game_txid, "green")) + input("Press [Enter] to continue...") + except Exception as e: + print("Something went wrong.") + print(e) + input("Press [Enter] to continue...") + + +def rogue_join_multiplayer_game(rpc_connection): + while True: + try: + print_multiplayer_games_list(rpc_connection) + # TODO: optional player data txid (print players you have and ask if you want to choose one) + game_txid = input("Input txid of game you want to join: ") + try: + while True: + print_players_list(rpc_connection) + is_choice_needed = input("Do you want to choose a player for this game? [y/n] ") + if is_choice_needed == "y": + player_txid = input("Please input player txid: ") + newgame_regisration_txid = rogue_game_register(rpc_connection, game_txid, player_txid)["txid"] + break + elif is_choice_needed == "n": + set_warriors_name(rpc_connection) + newgame_regisration_txid = rogue_game_register(rpc_connection, game_txid)["txid"] + break + else: + print("Please choose y or n !") + except Exception as e: + print("Something went wrong. Maybe you're trying to register on game twice or don't have enough funds to pay buyin.") + print(e) + input("Press [Enter] to continue...") + break + print(colorize("Succesfully registered.", "green")) + while True: + mempool = rpc_connection.getrawmempool() + if newgame_regisration_txid in mempool: + print(colorize("Waiting for registration transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Registration transaction is mined", "green")) + break + print(newgame_regisration_txid) + input("Press [Enter] to continue...") + break + except KeyboardInterrupt: + break + + +def print_players_list(rpc_connection): + players_list = rogue_players_list(rpc_connection) + print(colorize("\nYou own " + str(players_list["numplayerdata"]) + " warriors\n", "blue")) + warrior_counter = 0 + for player in players_list["playerdata"]: + warrior_counter = warrior_counter + 1 + player_data = rogue_player_info(rpc_connection, player)["player"] + print(colorize("\n================================\n","green")) + print("Warrior " + str(warrior_counter)) + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n","blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + input("Press [Enter] to continue...") + + +def sell_warrior(rpc_connection): + print(colorize("Your brave warriors: \n", "blue")) + print_players_list(rpc_connection) + print("\n") + while True: + need_sell = input("Do you want to place order to sell any? [y/n]: ") + if need_sell == "y": + playertxid = input("Input playertxid of warrior you want to sell: ") + price = input("Input price (in ROGUE coins) you want to sell warrior for: ") + try: + tokenid = rogue_player_info(rpc_connection, playertxid)["player"]["tokenid"] + except Exception as e: + print(e) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + token_ask_raw = rpc_connection.tokenask("1", tokenid, price) + try: + token_ask_txid = rpc_connection.sendrawtransaction(token_ask_raw["hex"]) + except Exception as e: + print(e) + print(token_ask_raw) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Ask succesfully placed. Ask txid is: " + token_ask_txid, "green")) + input("Press [Enter] to continue...") + break + if need_sell == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +#TODO: have to combine into single scanner with different cases +def is_warrior_alive(rpc_connection, warrior_txid): + warrior_alive = False + raw_transaction = rpc_connection.getrawtransaction(warrior_txid, 1) + for vout in raw_transaction["vout"]: + if vout["value"] == 0.00000001 and rpc_connection.gettxout(raw_transaction["txid"], vout["n"]): + warrior_alive = True + return warrior_alive + + +def warriors_scanner(rpc_connection): + start_time = time.time() + token_list = rpc_connection.tokenlist() + my_warriors_list = rogue_players_list(rpc_connection) + warriors_list = {} + for token in token_list: + player_info = rogue_player_info(rpc_connection, token) + if "status" in player_info and player_info["status"] == "error": + pass + elif player_info["player"]["playertxid"] in my_warriors_list["playerdata"]: + pass + elif not is_warrior_alive(rpc_connection, player_info["player"]["playertxid"]): + pass + else: + warriors_list[token] = player_info["player"] + print("--- %s seconds ---" % (time.time() - start_time)) + return warriors_list + + +def warriors_scanner_for_rating(rpc_connection): + print("It can take some time") + token_list = rpc_connection.tokenlist() + my_warriors_list = rogue_players_list(rpc_connection) + actual_playerids = [] + warriors_list = {} + for token in token_list: + player_info = rogue_player_info(rpc_connection, token) + if "status" in player_info and player_info["status"] == "error": + pass + else: + while True: + if "batontxid" in player_info["player"].keys(): + player_info = rogue_player_info(rpc_connection, player_info["player"]["batontxid"]) + else: + actual_playerids.append(player_info["player"]["playertxid"]) + break + for player_id in actual_playerids: + player_info = rogue_player_info(rpc_connection, player_id) + if not is_warrior_alive(rpc_connection, player_info["player"]["playertxid"]): + pass + else: + warriors_list[player_id] = player_info["player"] + return warriors_list + + +def warriors_scanner_for_dex(rpc_connection): + start_time = time.time() + token_list = rpc_connection.tokenlist() + my_warriors_list = rogue_players_list(rpc_connection) + warriors_list = {} + for token in token_list: + player_info = rogue_player_info(rpc_connection, token) + if "status" in player_info and player_info["status"] == "error": + pass + elif player_info["player"]["tokenid"] in my_warriors_list["playerdata"]: + pass + else: + warriors_list[token] = player_info["player"] + print("--- %s seconds ---" % (time.time() - start_time)) + return warriors_list + + +def print_warrior_list(rpc_connection): + players_list = warriors_scanner(rpc_connection) + print(colorize("All warriors on ROGUE chain: \n", "blue")) + warrior_counter = 0 + for player in players_list: + warrior_counter = warrior_counter + 1 + player_data = rogue_player_info(rpc_connection, player)["player"] + print(colorize("\n================================\n","green")) + print("Warrior " + str(warrior_counter)) + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n","blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + input("Press [Enter] to continue...") + + +def place_bid_on_warriror(rpc_connection): + warriors_list = print_warrior_list(rpc_connection) + # TODO: have to drop my warriors or at least print my warriors ids + while True: + need_buy = input("Do you want to place order to buy some warrior? [y/n]: ") + if need_buy == "y": + playertxid = input("Input playertxid of warrior you want to place bid for: ") + price = input("Input price (in ROGUE coins) you want to buy warrior for: ") + tokenid = rogue_player_info(rpc_connection, playertxid)["player"]["tokenid"] + token_bid_raw = rpc_connection.tokenbid("1", tokenid, price) + try: + token_bid_txid = rpc_connection.sendrawtransaction(token_bid_raw["hex"]) + except Exception as e: + print(e) + print(token_bid_raw) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Bid succesfully placed. Bid txid is: " + token_bid_txid, "green")) + input("Press [Enter] to continue...") + break + if need_buy == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def check_incoming_bids(rpc_connection): + # TODO: have to scan for warriors which are in asks as well + players_list = rogue_players_list(rpc_connection) + incoming_orders = [] + for player in players_list["playerdata"]: + token_id = rogue_player_info(rpc_connection, player)["player"]["tokenid"] + orders = rpc_connection.tokenorders(token_id) + if len(orders) > 0: + for order in orders: + if order["funcid"] == "b": + incoming_orders.append(order) + return incoming_orders + + +def print_icoming_bids(rpc_connection): + incoming_bids = check_incoming_bids(rpc_connection) + for bid in incoming_bids: + print("Recieved bid for warrior " + bid["tokenid"]) + player_data = rogue_player_info(rpc_connection, bid["tokenid"])["player"] + print(colorize("\n================================\n", "green")) + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("\n================================\n", "blue")) + print("Order info: \n") + print("Bid txid: " + bid["txid"]) + print("Price: " + str(bid["price"]) + "\n") + if len(incoming_bids) == 0: + print(colorize("There is no any incoming orders!", "blue")) + input("Press [Enter] to continue...") + else: + while True: + want_to_sell = input("Do you want to fill any incoming bid? [y/n]: ") + if want_to_sell == "y": + bid_txid = input("Input bid txid you want to fill: ") + for bid in incoming_bids: + if bid_txid == bid["txid"]: + tokenid = bid["tokenid"] + fill_sum = bid["totalrequired"] + fillbid_hex = rpc_connection.tokenfillbid(tokenid, bid_txid, str(fill_sum)) + try: + fillbid_txid = rpc_connection.sendrawtransaction(fillbid_hex["hex"]) + except Exception as e: + print(e) + print(fillbid_hex) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Warrior succesfully sold. Txid is: " + fillbid_txid, "green")) + input("Press [Enter] to continue...") + break + if want_to_sell == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def find_warriors_asks(rpc_connection): + warriors_list = warriors_scanner_for_dex(rpc_connection) + warriors_asks = [] + for player in warriors_list: + orders = rpc_connection.tokenorders(player) + if len(orders) > 0: + for order in orders: + if order["funcid"] == "s": + warriors_asks.append(order) + for ask in warriors_asks: + print(colorize("\n================================\n", "green")) + print("Warrior selling on marketplace: " + ask["tokenid"]) + player_data = rogue_player_info(rpc_connection, ask["tokenid"])["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("Order info: \n", "red")) + print("Ask txid: " + ask["txid"]) + print("Price: " + str(ask["price"]) + "\n") + while True: + want_to_buy = input("Do you want to buy any warrior? [y/n]: ") + if want_to_buy == "y": + ask_txid = input("Input asktxid which you want to fill: ") + for ask in warriors_asks: + if ask_txid == ask["txid"]: + tokenid = ask["tokenid"] + try: + fillask_raw = rpc_connection.tokenfillask(tokenid, ask_txid, "1") + except Exception as e: + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + try: + fillask_txid = rpc_connection.sendrawtransaction(fillask_raw["hex"]) + except Exception as e: + print(e) + print(fillask_raw) + print("Something went wrong. Be careful with input next time.") + input("Press [Enter] to continue...") + break + print(colorize("Warrior succesfully bought. Txid is: " + fillask_txid, "green")) + input("Press [Enter] to continue...") + break + if want_to_buy == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def warriors_orders_check(rpc_connection): + my_orders_list = rpc_connection.mytokenorders("17") + warriors_orders = {} + for order in my_orders_list: + player_info = rogue_player_info(rpc_connection, order["tokenid"]) + if "status" in player_info and player_info["status"] == "error": + pass + else: + warriors_orders[order["tokenid"]] = order + bids_list = [] + asks_list = [] + for order in warriors_orders: + if warriors_orders[order]["funcid"] == "s": + asks_list.append(warriors_orders[order]) + else: + bids_list.append(order) + print(colorize("\nYour asks:\n", "blue")) + print(colorize("\n********************************\n", "red")) + for ask in asks_list: + print("txid: " + ask["txid"]) + print("Price: " + ask["price"]) + print("Warrior tokenid: " + ask["tokenid"]) + print(colorize("\n================================\n", "green")) + print("Warrior selling on marketplace: " + ask["tokenid"]) + player_data = rogue_player_info(rpc_connection, ask["tokenid"])["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("\n================================\n", "green")) + print(colorize("\nYour bids:\n", "blue")) + print(colorize("\n********************************\n", "red")) + for bid in bids_list: + print("txid: " + bid["txid"]) + print("Price: " + bid["price"]) + print("Warrior tokenid: " + bid["tokenid"]) + print(colorize("\n================================\n", "green")) + print("Warrior selling on marketplace: " + bid["tokenid"]) + player_data = rogue_player_info(rpc_connection, bid["tokenid"])["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print(colorize("\nInventory:\n", "blue")) + for item in player_data["pack"]: + print(item) + print("\nTotal packsize: " + str(player_data["packsize"]) + "\n") + print(colorize("\n================================\n", "green")) + while True: + need_order_change = input("Do you want to cancel any of your orders? [y/n]: ") + if need_order_change == "y": + while True: + ask_or_bid = input("Do you want cancel ask or bid? [a/b]: ") + if ask_or_bid == "a": + ask_txid = input("Input txid of ask you want to cancel: ") + warrior_tokenid = input("Input warrior token id for this ask: ") + try: + ask_cancellation_hex = rpc_connection.tokencancelask(warrior_tokenid, ask_txid) + ask_cancellation_txid = rpc_connection.sendrawtransaction(ask_cancellation_hex["hex"]) + except Exception as e: + print(colorize("Please re-check your input!", "red")) + print(colorize("Ask succefully cancelled. Cancellation txid: " + ask_cancellation_txid, "green")) + break + if ask_or_bid == "b": + bid_txid = input("Input txid of bid you want to cancel: ") + warrior_tokenid = input("Input warrior token id for this bid: ") + try: + bid_cancellation_hex = rpc_connection.tokencancelbid(warrior_tokenid, bid_txid) + bid_cancellation_txid = rpc_connection.sendrawtransaction(bid_cancellation_hex["hex"]) + except Exception as e: + print(colorize("Please re-check your input!", "red")) + print(colorize("Bid succefully cancelled. Cancellation txid: " + bid_cancellation_txid, "green")) + break + else: + print(colorize("Choose a or b!", "red")) + input("Press [Enter] to continue...") + break + if need_order_change == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def set_warriors_name(rpc_connection): + warriors_name = input("What warrior name do you want for legends and tales about your brave adventures?: ") + warrior_name_arg = '"' + "[%22" + warriors_name + "%22]" + '"' + set_name_status = rpc_connection.cclib("setname", "17", warrior_name_arg) + print(colorize("Warrior name succesfully set", "green")) + print("Result: " + set_name_status["result"]) + print("Name: " + set_name_status["pname"]) + input("Press [Enter] to continue...") + + +def top_warriors_rating(rpc_connection): + start_time = time.time() + warriors_list = warriors_scanner_for_rating(rpc_connection) + warriors_exp = {} + for warrior in warriors_list: + warriors_exp[warrior] = warriors_list[warrior]["experience"] + warriors_exp_sorted = {} + temp = [(k, warriors_exp[k]) for k in sorted(warriors_exp, key=warriors_exp.get, reverse=True)] + for k,v in temp: + warriors_exp_sorted[k] = v + counter = 0 + for experienced_warrior in warriors_exp_sorted: + if counter < 20: + counter = counter + 1 + print("\n" + str(counter) + " place.") + print(colorize("\n================================\n", "blue")) + player_data = rogue_player_info(rpc_connection, experienced_warrior)["player"] + print("Name: " + player_data["pname"] + "\n") + print("Player txid: " + player_data["playertxid"]) + print("Token txid: " + player_data["tokenid"]) + print("Hitpoints: " + str(player_data["hitpoints"])) + print("Strength: " + str(player_data["strength"])) + print("Level: " + str(player_data["level"])) + print("Experience: " + str(player_data["experience"])) + print("Dungeon Level: " + str(player_data["dungeonlevel"])) + print("Chain: " + player_data["chain"]) + print("--- %s seconds ---" % (time.time() - start_time)) + input("Press [Enter] to continue...") + + +def exit(): + sys.exit() + + +def warrior_trasnfer(rpc_connection): + print(colorize("Your brave warriors: \n", "blue")) + print_players_list(rpc_connection) + print("\n") + while True: + need_transfer = input("Do you want to transfer any warrior? [y/n]: ") + if need_transfer == "y": + warrior_tokenid = input("Input warrior tokenid: ") + recepient_pubkey = input("Input recepient pubkey: ") + try: + token_transfer_hex = rpc_connection.tokentransfer(warrior_tokenid, recepient_pubkey, "1") + token_transfer_txid = rpc_connection.sendrawtransaction(token_transfer_hex["hex"]) + except Exception as e: + print(e) + print("Something went wrong. Please be careful with your input next time!") + input("Press [Enter] to continue...") + break + print(colorize("Warrior succesfully transferred! Transfer txid: " + token_transfer_txid, "green")) + input("Press [Enter] to continue...") + break + if need_transfer == "n": + print("As you wish!") + input("Press [Enter] to continue...") + break + else: + print(colorize("Choose y or n!", "red")) + + +def check_if_config_is_here(rpc_connection, assetchain_name): + config_name = assetchain_name + ".conf" + if os.path.exists(config_name): + print(colorize("Config is already in daemon folder", "green")) + else: + if operating_system == 'Darwin': + path_to_config = os.environ['HOME'] + '/Library/Application Support/Komodo/' + assetchain_name + '/' + config_name + elif operating_system == 'Linux': + path_to_config = os.environ['HOME'] + '/.komodo/' + assetchain_name + '/' + config_name + elif operating_system == 'Win64' or operating_system == 'Windows': + path_to_config = '%s/komodo/' + assetchain_name + '/' + config_name % os.environ['APPDATA'] + try: + copy(path_to_config, os.getcwd()) + except Exception as e: + print(e) + print("Can't copy config to current daemon directory automatically by some reason.") + print("Please copy it manually. It's locating here: " + path_to_config) + + +def find_game_keystrokes_in_log(gametxid): + + operating_system = platform.system() + if operating_system == 'Win64' or operating_system == 'Windows': + p1 = subprocess.Popen(["type", "keystrokes.log"], stdout=subprocess.PIPE, shell=True) + p2 = subprocess.Popen(["findstr", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE, shell=True) + else: + p1 = subprocess.Popen(["cat", "keystrokes.log"], stdout=subprocess.PIPE) + p2 = subprocess.Popen(["grep", gametxid], stdin=p1.stdout, stdout=subprocess.PIPE) + p1.stdout.close() + output = p2.communicate()[0] + keystrokes_log_for_game = bytes.decode(output).split("\n") + return keystrokes_log_for_game + + +def check_if_tx_in_mempool(rpc_connection, txid): + while True: + mempool = rpc_connection.getrawmempool() + if txid in mempool: + print(colorize("Waiting for " + txid + " transaction to be mined", "blue")) + time.sleep(5) + else: + print(colorize("Transaction is mined", "green")) + break diff --git a/src/tui/requirements.txt b/src/tui/requirements.txt new file mode 100644 index 000000000..734da529c --- /dev/null +++ b/src/tui/requirements.txt @@ -0,0 +1,8 @@ +configobj==5.0.6 +pip==9.0.1 +pycurl==7.43.0.2 +setuptools==39.0.1 +six==1.12.0 +slick-bitcoinrpc==0.1.4 +ujson==1.35 +wheel==0.32.3 diff --git a/src/tui/tui_assets.py b/src/tui/tui_assets.py new file mode 100755 index 000000000..091484a40 --- /dev/null +++ b/src/tui/tui_assets.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + + +header = "\ + ___ _ _____ \n\ + / _ \ | | / __ \\\n\ +/ /_\ \ ___ ___ ___ | |_ ___ | / \/\n\ +| _ |/ __|/ __| / _ \| __|/ __|| | \n\ +| | | |\__ \\\__ \| __/| |_ \__ \| \__/\\\n\ +\_| |_/|___/|___/ \___| \__||___/ \____/\n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Print tokens list": tuilib.print_tokens_list}, + {"Check my tokens balances" : tuilib.print_tokens_balances}, + # transfer tokens (pre-print tokens balances) + {"Create token": tuilib.token_create_tui}, + # trading zone - pre-print token orders - possible to open order or fill existing one + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2 by Anton Lysakov\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() + diff --git a/src/tui/tui_gateways_creation.py b/src/tui/tui_gateways_creation.py new file mode 100755 index 000000000..7bb489c7f --- /dev/null +++ b/src/tui/tui_gateways_creation.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + +header = "\ + _____ _ _____ _____ \n\ +| __ \ | | / __ \/ __ \\\n\ +| | \/ __ _| |_ _____ ____ _ _ _ ___| / \/| / \/\n\ +| | __ / _` | __/ _ \ \ /\ / / _` | | | / __| | | | \n\ +| |_\ \ (_| | || __/\ V V / (_| | |_| \__ \ \__/\| \__/\\\n\ + \____/\__,_|\__\___| \_/\_/ \__,_|\__, |___/\____/ \____/\n\ + __/ | \n\ + |___/ \n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Create token": tuilib.token_create_tui}, + {"Create oracle": tuilib.oracle_create_tui}, + {"Register as publisher for oracle": tuilib.oracle_register_tui}, + {"Subscribe on oracle (+UTXO generator)": tuilib.oracle_subscription_utxogen}, + {"Bind Gateway": tuilib.gateways_bind_tui}, + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_gateways_usage.py b/src/tui/tui_gateways_usage.py new file mode 100755 index 000000000..0c989e3af --- /dev/null +++ b/src/tui/tui_gateways_usage.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os, time + +header = "\ + _____ _ _____ _____ \n\ +| __ \ | | / __ \/ __ \\\n\ +| | \/ __ _| |_ _____ ____ _ _ _ ___| / \/| / \/\n\ +| | __ / _` | __/ _ \ \ /\ / / _` | | | / __| | | | \n\ +| |_\ \ (_| | || __/\ V V / (_| | |_| \__ \ \__/\| \__/\\\n\ + \____/\__,_|\__\___| \_/\_/ \__,_|\__, |___/\____/ \____/\n\ + __/ | \n\ + |___/ \n" + +menuItems = [ + {"Check connection to assetchain": tuilib.getinfo_tui}, + {"Check assetchain mempool": tuilib.print_mempool}, + {"Check connection to KMD": tuilib.getinfo_tui}, + {"Connect to KMD daemon": tuilib.rpc_kmd_connection_tui}, + {"Send KMD gateway deposit transaction": tuilib.gateways_send_kmd}, + {"Execute gateways deposit": tuilib.gateways_deposit_tui}, + {"Execute gateways claim": tuilib.gateways_claim_tui}, + {"Execute gateways withdrawal": tuilib.gateways_withdrawal_tui}, + {"Exit": exit} +] + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + # We have to call KMD specific functions with connection to KMD daemon + elif list(menuItems[int(choice)].keys())[0] == "Connect to KMD daemon": + rpc_connection_kmd = list(menuItems[int(choice)].values())[0]() + elif list(menuItems[int(choice)].keys())[0] == "Check connection to KMD": + while True: + try: + list(menuItems[int(choice)].values())[0](rpc_connection_kmd) + break + except Exception as e: + print("Please connect to KMD daemon first!") + input("Press [Enter] to continue...") + break + elif list(menuItems[int(choice)].keys())[0] == "Send KMD gateway deposit transaction": + while True: + try: + list(menuItems[int(choice)].values())[0](rpc_connection_kmd) + break + except Exception as e: + print(e) + print("Please connect to KMD daemon first!") + input("Press [Enter] to continue...") + break + elif list(menuItems[int(choice)].keys())[0] == "Execute gateways deposit": + while True: + try: + list(menuItems[int(choice)].values())[0](rpc_connection, rpc_connection_kmd) + break + except Exception as e: + print(e) + print("Please connect to KMD daemon first!") + input("Press [Enter] to continue...") + break + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\nPlease provide RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_marmara.py b/src/tui/tui_marmara.py new file mode 100755 index 000000000..cfe628890 --- /dev/null +++ b/src/tui/tui_marmara.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + + +header = "\ +___ ___ _____ _ _ _____ \n\ +| \/ | |_ _| | | |_ _|\n\ +| . . | __ _ _ __ _ __ ___ __ _ _ __ __ _ | | | | | | | |\n\ +| |\/| |/ _` | '__| '_ ` _ \ / _` | '__/ _` | | | | | | | | |\n\ +| | | | (_| | | | | | | | | (_| | | | (_| | | | | |_| |_| |_\n\ +\_| |_/\__,_|_| |_| |_| |_|\__,_|_| \__,_| \_/ \___/ \___/\n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Check MARMARA info": tuilib.marmara_info_tui}, + {"Lock funds for MARMARA": tuilib.marmara_lock_tui}, + {"Request MARMARA cheque": tuilib.marmara_receive_tui}, + {"Issue MARMARA cheque": tuilib.marmara_issue_tui}, + {"Check credit loop status": tuilib.marmara_creditloop_tui}, + {"Settle MARMARA loop": tuilib.marmara_settlement_tui}, + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.1\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + chain = input("Input assetchain name (-ac_name= value) you want to work with: ") + try: + print(tuilib.colorize("Welcome to the MarmaraCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.def_credentials(chain) + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_oracles.py b/src/tui/tui_oracles.py new file mode 100755 index 000000000..fec874d35 --- /dev/null +++ b/src/tui/tui_oracles.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time + +header = "\ + _____ _ _____ _____ \n\ +| _ | | | / __ \/ __ \\\n\ +| | | | _ __ __ _ ___ | | ___ ___ | / \/| / \/\n\ +| | | || '__| / _` | / __|| | / _ \/ __|| | | |\n\ +\ \_/ /| | | (_| || (__ | || __/\__ \| \__/\| \__/\\\n\ + \___/ |_| \__,_| \___||_| \___||___/ \____/ \____/\n" + +menuItems = [ + # TODO: Have to implement here native oracle file uploader / reader, should be dope + # TODO: data publisher / converter for different types + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Create oracle": tuilib.oracle_create_tui}, + {"Register as publisher for oracle": tuilib.oracle_register_tui}, + {"Subscribe on oracle (+UTXO generator)": tuilib.oracle_subscription_utxogen}, + {"Upload file to oracle": tuilib.convert_file_oracle_D}, + {"Display list of files uploaded to this AC": tuilib.display_files_list}, + {"Download files from oracle": tuilib.files_downloader}, + {"Exit": exit} +] + + +def main(): + while True: + os.system('clear') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('CLI version 0.2 by Anton Lysakov\n', 'green')) + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + try: + print(tuilib.colorize("Welcome to the GatewaysCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.rpc_connection_tui() + rpclib.getinfo(rpc_connection) + except Exception: + print(tuilib.colorize("Cant connect to RPC! Please re-check credentials.", "pink")) + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_rogue.py b/src/tui/tui_rogue.py new file mode 100755 index 000000000..9942369e2 --- /dev/null +++ b/src/tui/tui_rogue.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time +import sys +import platform + +header = "\ +______ _____ _____ \n\ +| ___ \ / __ \/ __ \\\n\ +| |_/ /___ __ _ _ _ ___| / \/| / \/\n\ +| // _ \ / _` | | | |/ _ \ | | |\n\ +| |\ \ (_) | (_| | |_| | __/ \__/\| \__/\\\n\ +\_| \_\___/ \__, |\__,_|\___|\____/ \____/\n\ + __/ |\n\ + |___/\n" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Check my warriors list": tuilib.print_players_list}, + {"Transfer warrior to other pubkey": tuilib.warrior_trasnfer}, + {"TOP-20 ROGUE Warriors": tuilib.top_warriors_rating}, + {"Set warriors name": tuilib.set_warriors_name}, + {"Start singleplayer training game (creating, registering and starting game)": tuilib.rogue_newgame_singleplayer}, + {"Create multiplayer game": tuilib.rogue_newgame_multiplayer}, + {"Join (register) multiplayer game": tuilib.rogue_join_multiplayer_game}, + {"Check my multiplayer games status / start": tuilib.play_multiplayer_game}, + {"Check if somebody wants to buy your warrior (incoming bids)": tuilib.print_icoming_bids}, + {"Place order to sell warrior": tuilib.sell_warrior}, + {"Place order to buy someones warrior": tuilib.place_bid_on_warriror}, + {"Check if somebody selling warrior": tuilib.find_warriors_asks}, + {"Check / cancel my warriors trade orders": tuilib.warriors_orders_check}, + # {"Manually exit the game (bailout)": "test"}, + # {"Manually claim ROGUE coins for game (highlander)": "test"}, + {"Exit": tuilib.exit} +] + +def main(): + while True: + operating_system = platform.system() + if operating_system != 'Win64' and operating_system != 'Windows': + os.system('clear') + else: + os.system('cls') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('TUI v0.0.3\n', 'green')) + menu_items_counter = 0 + for item in menuItems: + if menu_items_counter == 0: + print("\nUtility:\n") + menu_items_counter = menu_items_counter + 1 + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + if menu_items_counter == 6: + print("\nNew singleplayer game:\n") + if menu_items_counter == 7: + print("\nMultiplayer games:\n") + if menu_items_counter == 10: + print("\nDEX features:\n") + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + chain = "ROGUE" + try: + print(tuilib.colorize("Welcome to the RogueCC TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.def_credentials(chain) + rpclib.getinfo(rpc_connection) + # waiting until chain is in sync + while True: + have_blocks = rpclib.getinfo(rpc_connection)["blocks"] + longest_chain = rpclib.getinfo(rpc_connection)["longestchain"] + if have_blocks != longest_chain: + print(tuilib.colorize("ROGUE not synced yet.", "red")) + print("Have " + str(have_blocks) + " from " + str(longest_chain) + " blocks") + time.sleep(5) + else: + print(tuilib.colorize("Chain is synced!", "green")) + break + # checking if pubkey is set and set valid if not + info = rpclib.getinfo(rpc_connection) + if "pubkey" in info.keys(): + print("Pubkey is already set") + else: + valid_address = rpc_connection.getaccountaddress("") + valid_pubkey = rpc_connection.validateaddress(valid_address)["pubkey"] + rpc_connection.setpubkey(valid_pubkey) + print(tuilib.colorize("Pubkey is succesfully set!", "green")) + # copy ROGUE config to current daemon directory if it's not here + tuilib.check_if_config_is_here(rpc_connection, "ROGUE") + except Exception: + print(tuilib.colorize("Cant connect to ROGUE daemon RPC! Please check if daemon is up.", "pink")) + tuilib.exit() + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main() diff --git a/src/tui/tui_tetris.py b/src/tui/tui_tetris.py new file mode 100755 index 000000000..3c42d4daa --- /dev/null +++ b/src/tui/tui_tetris.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +from lib import rpclib, tuilib +import os +import time +import sys +import platform + +header = "\ + _____ _ _ ______\n\ +|_ _| | | (_) | _ \n\ + | | ___| |_ _ __ _ ___| | | |__ _ _ __ _ __\n\ + | |/ _ \ __| '__| / __| | | / _` | '_ \| '_ \\\n\ + | | __/ |_| | | \__ \ |/ / (_| | |_) | |_) |\n\ + \_/\___|\__|_| |_|___/___/ \__,_| .__/| .__/\n\ + | | | |\n\ + |_| |_|" + + +menuItems = [ + {"Check current connection": tuilib.getinfo_tui}, + {"Check mempool": tuilib.print_mempool}, + {"Start singleplayer tetris game (creating, registering and starting game)": tuilib.rogue_newgame_singleplayer}, + {"Exit": tuilib.exit} +] + + +def main(): + while True: + operating_system = platform.system() + if operating_system != 'Win64' and operating_system != 'Windows': + os.system('clear') + else: + os.system('cls') + print(tuilib.colorize(header, 'pink')) + print(tuilib.colorize('TUI v0.0.3\n', 'green')) + menu_items_counter = 0 + for item in menuItems: + print(tuilib.colorize("[" + str(menuItems.index(item)) + "] ", 'blue') + list(item.keys())[0]) + choice = input(">> ") + try: + if int(choice) < 0: + raise ValueError + # Call the matching function + if list(menuItems[int(choice)].keys())[0] == "Exit": + list(menuItems[int(choice)].values())[0]() + elif list(menuItems[int(choice)].keys())[0] == "Start singleplayer tetris game (creating, registering and starting game)": + list(menuItems[int(choice)].values())[0](rpc_connection, False) + else: + list(menuItems[int(choice)].values())[0](rpc_connection) + except (ValueError, IndexError): + pass + + +if __name__ == "__main__": + while True: + chain = "GTEST" + try: + print(tuilib.colorize("Welcome to the Tetris TUI!\n" + "Please provide asset chain RPC connection details for initialization", "blue")) + rpc_connection = tuilib.def_credentials(chain) + rpclib.getinfo(rpc_connection) + # waiting until chain is in sync + while True: + have_blocks = rpclib.getinfo(rpc_connection)["blocks"] + longest_chain = rpclib.getinfo(rpc_connection)["longestchain"] + if have_blocks != longest_chain: + print(tuilib.colorize("GTEST not synced yet.", "red")) + print("Have " + str(have_blocks) + " from " + str(longest_chain) + " blocks") + time.sleep(5) + else: + print(tuilib.colorize("Chain is synced!", "green")) + break + # checking if pubkey is set and set valid if not + info = rpclib.getinfo(rpc_connection) + if "pubkey" in info.keys(): + print("Pubkey is already set") + else: + valid_address = rpc_connection.getaccountaddress("") + valid_pubkey = rpc_connection.validateaddress(valid_address)["pubkey"] + rpc_connection.setpubkey(valid_pubkey) + print(tuilib.colorize("Pubkey is succesfully set!", "green")) + # copy ROGUE config to current daemon directory if it's not here + tuilib.check_if_config_is_here(rpc_connection, "GTEST") + except Exception: + print(tuilib.colorize("Cant connect to GTEST daemon RPC! Please check if daemon is up.", "pink")) + tuilib.exit() + else: + print(tuilib.colorize("Succesfully connected!\n", "green")) + with (open("lib/logo.txt", "r")) as logo: + for line in logo: + print(line, end='') + time.sleep(0.04) + print("\n") + break + main()