Delete more CCs #381
This commit is contained in:
@@ -35,9 +35,6 @@ std::string MYCCLIBNAME = (char *)"rogue";
|
|||||||
#elif BUILD_CUSTOMCC
|
#elif BUILD_CUSTOMCC
|
||||||
#include "customcc.h"
|
#include "customcc.h"
|
||||||
|
|
||||||
#elif BUILD_GAMESCC
|
|
||||||
#include "gamescc.h"
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define EVAL_SUDOKU 17
|
#define EVAL_SUDOKU 17
|
||||||
#define EVAL_MUSIG 18
|
#define EVAL_MUSIG 18
|
||||||
|
|||||||
@@ -1,292 +0,0 @@
|
|||||||
// Copyright (c) 2016-2023 The Hush developers
|
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
||||||
|
|
||||||
#include "prices.h"
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#ifdef BUILD_GAMESCC
|
|
||||||
#include "../rogue/cursesd.h"
|
|
||||||
#else
|
|
||||||
#include <curses.h>
|
|
||||||
#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 <ncurses.h>
|
|
||||||
#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 *)"<nullstr>";
|
|
||||||
}
|
|
||||||
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= hush_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= hush_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
|
|
||||||
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
// Copyright (c) 2016-2023 The Hush developers
|
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
||||||
/******************************************************************************
|
|
||||||
* 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<uint8_t> 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= hush_chainactive(height)) != 0 )
|
|
||||||
{
|
|
||||||
if ( hush_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<n; i++)
|
|
||||||
{
|
|
||||||
tx = block.vtx[i];
|
|
||||||
if ( myGetTransaction(tx.vin[vini].prevout.hash,vintx,hashBlock) == 0 )
|
|
||||||
continue;
|
|
||||||
else if ( tx.vin[vini].prevout.n >= 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 = hush_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(), hush_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<uint8_t> 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<len&&i<sizeof(price); i++)
|
|
||||||
((uint8_t *)&price)[7-i] = payload[i];
|
|
||||||
prices_update((uint32_t)(price >> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
// Copyright (c) 2016-2023 The Hush developers
|
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
||||||
@@ -1,907 +0,0 @@
|
|||||||
// Copyright (c) 2016-2023 The Hush developers
|
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
||||||
|
|
||||||
#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 <stdio.h> // for FILE
|
|
||||||
#include <stdbool.h> // for bool
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#ifdef BUILD_GAMESCC
|
|
||||||
#include "../rogue/cursesd.h"
|
|
||||||
#else
|
|
||||||
#include <curses.h>
|
|
||||||
#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 *)"<nullstr>";
|
|
||||||
}
|
|
||||||
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= hush_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
|
|
||||||
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
// Copyright (c) 2016-2023 The Hush developers
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* 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<uint8_t> 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<len; i++)
|
|
||||||
// fprintf(stderr,"%02x",payload[i]);
|
|
||||||
//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);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniValue games_bet(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
|
||||||
{
|
|
||||||
UniValue result;
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
UniValue games_settle(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
|
||||||
{
|
|
||||||
UniValue result;
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool games_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
|
||||||
{
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,211 +0,0 @@
|
|||||||
// Copyright (c) 2016-2023 The Hush developers
|
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
||||||
|
|
||||||
#ifndef H_TETRIS_H
|
|
||||||
#define H_TETRIS_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 "tetris" // name of executable
|
|
||||||
#define GAMEMAIN tetris // main program of game
|
|
||||||
#define GAMEPLAYERJSON tetrisplayerjson // displays game specific json
|
|
||||||
#define GAMEDATA tetrisdata // extracts data from game specific variables into games_state
|
|
||||||
#define CHAINNAME "GTEST" // -ac_name=
|
|
||||||
typedef uint16_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
|
|
||||||
|
|
||||||
123
src/cc/gamescc.h
123
src/cc/gamescc.h
@@ -1,123 +0,0 @@
|
|||||||
// Copyright (c) 2016-2023 The Hush developers
|
|
||||||
// Distributed under the GPLv3 software license, see the accompanying
|
|
||||||
// file COPYING or https://www.gnu.org/licenses/gpl-3.0.en.html
|
|
||||||
#ifndef H_GAMESCC_H
|
|
||||||
#define H_GAMESCC_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#define GAMES_RNGMULT 11109
|
|
||||||
#define GAMES_RNGOFFSET 13849
|
|
||||||
#define GAMES_MAXRNGS 10000
|
|
||||||
|
|
||||||
#ifndef STANDALONE
|
|
||||||
|
|
||||||
#define ENABLE_WALLET
|
|
||||||
extern CWallet* pwalletMain;
|
|
||||||
|
|
||||||
#include "CCinclude.h"
|
|
||||||
#include "secp256k1.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define EVAL_GAMES (EVAL_FAUCET2+1)
|
|
||||||
#define GAMES_TXFEE 10000
|
|
||||||
#define GAMES_MAXITERATIONS 777
|
|
||||||
#define GAMES_MAXKEYSTROKESGAP 60
|
|
||||||
#define GAMES_MAXPLAYERS 64
|
|
||||||
#define GAMES_REGISTRATIONSIZE (100 * 10000)
|
|
||||||
#define GAMES_REGISTRATION 1
|
|
||||||
|
|
||||||
|
|
||||||
#define MYCCNAME "games"
|
|
||||||
|
|
||||||
std::string Games_pname;
|
|
||||||
|
|
||||||
#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 }, \
|
|
||||||
{ (char *)MYCCNAME, (char *)"setname", (char *)"pname", 1, 1, ' ', EVAL_GAMES }, \
|
|
||||||
{ (char *)MYCCNAME, (char *)"newgame", (char *)"maxplayers,buyin", 2, 2, 'C', EVAL_GAMES }, \
|
|
||||||
{ (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 *)"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);
|
|
||||||
UniValue games_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
|
|
||||||
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_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 ) \
|
|
||||||
{ \
|
|
||||||
if ( strcmp(method,"rng") == 0 ) \
|
|
||||||
return(games_rng(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"rngnext") == 0 ) \
|
|
||||||
return(games_rngnext(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"newgame") == 0 ) \
|
|
||||||
return(games_newgame(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"gameinfo") == 0 ) \
|
|
||||||
return(games_gameinfo(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"register") == 0 ) \
|
|
||||||
return(games_register(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"events") == 0 ) \
|
|
||||||
return(games_events(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"players") == 0 ) \
|
|
||||||
return(games_players(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"games") == 0 ) \
|
|
||||||
return(games_games(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"pending") == 0 ) \
|
|
||||||
return(games_pending(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"setname") == 0 ) \
|
|
||||||
return(games_setname(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"playerinfo") == 0 ) \
|
|
||||||
return(games_playerinfo(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"keystrokes") == 0 ) \
|
|
||||||
return(games_keystrokes(txfee,cp,params)); \
|
|
||||||
else if ( strcmp(method,"extract") == 0 ) \
|
|
||||||
return(games_extract(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")); \
|
|
||||||
return(result); \
|
|
||||||
} \
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
580
src/cc/musig.cpp
580
src/cc/musig.cpp
@@ -202,14 +202,6 @@ struct secp256k1_context_struct {
|
|||||||
//#include "../secp256k1/include/secp256k1_schnorrsig.h"
|
//#include "../secp256k1/include/secp256k1_schnorrsig.h"
|
||||||
#include "../secp256k1/include/secp256k1_musig.h"
|
#include "../secp256k1/include/secp256k1_musig.h"
|
||||||
|
|
||||||
|
|
||||||
extern "C" int secp256k1_ecmult_multi_var(const secp256k1_ecmult_context *ctx, secp256k1_scratch *scratch, secp256k1_gej *r, const secp256k1_scalar *inp_g_sc, secp256k1_ecmult_multi_callback cb, void *cbdata, size_t n);
|
|
||||||
extern "C" int secp256k1_schnorrsig_verify(const secp256k1_context* ctx, const secp256k1_schnorrsig *sig, const unsigned char *msg32, const secp256k1_pubkey *pk);
|
|
||||||
extern "C" int secp256k1_schnorrsig_parse(const secp256k1_context* ctx, secp256k1_schnorrsig* sig, const unsigned char *in64);
|
|
||||||
extern "C" int secp256k1_musig_pubkey_combine(const secp256k1_context* ctx, secp256k1_scratch_space *scratch, secp256k1_pubkey *combined_pk, unsigned char *pk_hash32, const secp256k1_pubkey *pubkeys, size_t n_pubkeys);
|
|
||||||
extern "C" int secp256k1_musig_session_initialize(const secp256k1_context* ctx, secp256k1_musig_session *session, secp256k1_musig_session_signer_data *signers, unsigned char *nonce_commitment32, const unsigned char *session_id32, const unsigned char *msg32, const secp256k1_pubkey *combined_pk, const unsigned char *pk_hash32, size_t n_signers, size_t my_index, const unsigned char *seckey);
|
|
||||||
extern "C" int secp256k1_schnorrsig_serialize(const secp256k1_context* ctx, unsigned char *out64, const secp256k1_schnorrsig* sig);
|
|
||||||
|
|
||||||
#define MUSIG_PREVN 0 // for now, just use vout0 for the musig output
|
#define MUSIG_PREVN 0 // for now, just use vout0 for the musig output
|
||||||
#define MUSIG_TXFEE 10000
|
#define MUSIG_TXFEE 10000
|
||||||
|
|
||||||
@@ -243,631 +235,107 @@ struct musig_info *musig_infocreate(int32_t myind,int32_t num)
|
|||||||
|
|
||||||
void musig_infofree(struct musig_info *mp)
|
void musig_infofree(struct musig_info *mp)
|
||||||
{
|
{
|
||||||
if ( mp->partial_sig != 0 )
|
|
||||||
{
|
|
||||||
GetRandBytes((uint8_t *)mp->partial_sig,mp->num*sizeof(*mp->partial_sig));
|
|
||||||
free(mp->partial_sig);
|
|
||||||
}
|
|
||||||
if ( mp->nonces != 0 )
|
|
||||||
{
|
|
||||||
GetRandBytes((uint8_t *)mp->nonces,mp->num*sizeof(*mp->nonces));
|
|
||||||
free(mp->nonces);
|
|
||||||
}
|
|
||||||
if ( mp->signer_data != 0 )
|
|
||||||
{
|
|
||||||
GetRandBytes((uint8_t *)mp->signer_data,mp->num*sizeof(*mp->signer_data));
|
|
||||||
free(mp->signer_data);
|
|
||||||
}
|
|
||||||
if ( mp->nonce_commitments != 0 )
|
|
||||||
{
|
|
||||||
GetRandBytes((uint8_t *)mp->nonce_commitments,mp->num*32);
|
|
||||||
free(mp->nonce_commitments);
|
|
||||||
}
|
|
||||||
if ( mp->commitment_ptrs != 0 )
|
|
||||||
{
|
|
||||||
GetRandBytes((uint8_t *)mp->commitment_ptrs,mp->num*sizeof(*mp->commitment_ptrs));
|
|
||||||
free(mp->commitment_ptrs);
|
|
||||||
}
|
|
||||||
GetRandBytes((uint8_t *)mp,sizeof(*mp));
|
|
||||||
free(mp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CScript musig_sendopret(uint8_t funcid,CPubKey pk)
|
CScript musig_sendopret(uint8_t funcid,CPubKey pk)
|
||||||
{
|
{
|
||||||
CScript opret; uint8_t evalcode = EVAL_MUSIG;
|
CScript opret;
|
||||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk);
|
|
||||||
return(opret);
|
return(opret);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t musig_sendopretdecode(CPubKey &pk,CScript scriptPubKey)
|
uint8_t musig_sendopretdecode(CPubKey &pk,CScript scriptPubKey)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> vopret; uint8_t e,f;
|
|
||||||
GetOpReturnData(scriptPubKey,vopret);
|
|
||||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk) != 0 && e == EVAL_MUSIG && f == 'x' )
|
|
||||||
{
|
|
||||||
return(f);
|
|
||||||
}
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CScript musig_spendopret(uint8_t funcid,CPubKey pk,std::vector<uint8_t> musig64)
|
CScript musig_spendopret(uint8_t funcid,CPubKey pk,std::vector<uint8_t> musig64)
|
||||||
{
|
{
|
||||||
CScript opret; uint8_t evalcode = EVAL_MUSIG;
|
CScript opret;
|
||||||
opret << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << pk << musig64);
|
|
||||||
return(opret);
|
return(opret);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t musig_spendopretdecode(CPubKey &pk,std::vector<uint8_t> &musig64,CScript scriptPubKey)
|
uint8_t musig_spendopretdecode(CPubKey &pk,std::vector<uint8_t> &musig64,CScript scriptPubKey)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> vopret; uint8_t e,f;
|
|
||||||
GetOpReturnData(scriptPubKey,vopret);
|
|
||||||
if ( vopret.size() > 2 && E_UNMARSHAL(vopret,ss >> e; ss >> f; ss >> pk; ss >> musig64) != 0 && e == EVAL_MUSIG && f == 'y' )
|
|
||||||
{
|
|
||||||
return(f);
|
|
||||||
}
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t musig_parsepubkey(secp256k1_context *ctx,secp256k1_pubkey &spk,cJSON *item)
|
int32_t musig_parsepubkey(secp256k1_context *ctx,secp256k1_pubkey &spk,cJSON *item)
|
||||||
{
|
{
|
||||||
char *hexstr;
|
return -1;
|
||||||
if ( (hexstr= jstr(item,0)) != 0 && is_hexstr(hexstr,0) == 66 )
|
|
||||||
{
|
|
||||||
CPubKey pk(ParseHex(hexstr));
|
|
||||||
if ( secp256k1_ec_pubkey_parse(ctx,&spk,pk.begin(),33) > 0 )
|
|
||||||
return(1);
|
|
||||||
} else return(-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t musig_msghash(uint8_t *msg,uint256 prevhash,int32_t prevn,CTxOut vout,CPubKey pk)
|
int32_t musig_msghash(uint8_t *msg,uint256 prevhash,int32_t prevn,CTxOut vout,CPubKey pk)
|
||||||
{
|
{
|
||||||
CScript data; uint256 hash; int32_t len = 0;
|
|
||||||
data << E_MARSHAL(ss << prevhash << prevn << vout << pk);
|
|
||||||
hash = Hash(data.begin(),data.end());
|
|
||||||
memcpy(msg,&hash,sizeof(hash));
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t musig_prevoutmsg(uint8_t *msg,uint256 sendtxid,CScript scriptPubKey)
|
int32_t musig_prevoutmsg(uint8_t *msg,uint256 sendtxid,CScript scriptPubKey)
|
||||||
{
|
{
|
||||||
CTransaction vintx; uint256 hashBlock; int32_t numvouts; CTxOut vout; CPubKey pk;
|
|
||||||
memset(msg,0,32);
|
|
||||||
if ( myGetTransaction(sendtxid,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
|
|
||||||
{
|
|
||||||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
|
|
||||||
{
|
|
||||||
vout.nValue = vintx.vout[MUSIG_PREVN].nValue - MUSIG_TXFEE;
|
|
||||||
vout.scriptPubKey = scriptPubKey;
|
|
||||||
return(musig_msghash(msg,sendtxid,MUSIG_PREVN,vout,pk));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_calcmsg(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
UniValue result(UniValue::VOBJ); uint256 sendtxid; int32_t i,zeros=0; uint8_t msg[32]; char *scriptstr,str[65]; int32_t n;
|
UniValue result(UniValue::VOBJ);
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
return result;
|
||||||
{
|
|
||||||
if ( n == 2 )
|
|
||||||
{
|
|
||||||
sendtxid = juint256(jitem(params,0));
|
|
||||||
scriptstr = jstr(jitem(params,1),0);
|
|
||||||
if ( is_hexstr(scriptstr,0) != 0 )
|
|
||||||
{
|
|
||||||
CScript scriptPubKey;
|
|
||||||
scriptPubKey.resize(strlen(scriptstr)/2);
|
|
||||||
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr);
|
|
||||||
musig_prevoutmsg(msg,sendtxid,scriptPubKey);
|
|
||||||
for (i=0; i<32; i++)
|
|
||||||
{
|
|
||||||
sprintf(&str[i<<1],"%02x",msg[i]);
|
|
||||||
if ( msg[i] == 0 )
|
|
||||||
zeros++;
|
|
||||||
}
|
|
||||||
str[64] = 0;
|
|
||||||
if ( zeros != 32 )
|
|
||||||
{
|
|
||||||
result.push_back(Pair("msg",str));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
return(result);
|
|
||||||
} else return(cclib_error(result,"null result, make sure params are sendtxid, scriptPubKey"));
|
|
||||||
} else return(cclib_error(result,"script is not hex"));
|
|
||||||
} else return(cclib_error(result,"need exactly 2 parameters: sendtxid, scriptPubKey"));
|
|
||||||
} else return(cclib_error(result,"couldnt parse params"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_combine(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
UniValue result(UniValue::VOBJ);
|
||||||
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
|
return result;
|
||||||
UniValue result(UniValue::VOBJ); CPubKey pk; int32_t i,n; uint8_t pkhash[32]; char *hexstr,str[67]; secp256k1_pubkey combined_pk,spk; std::vector<secp256k1_pubkey> pubkeys;
|
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
|
||||||
{
|
|
||||||
//fprintf(stderr,"n.%d args.(%s)\n",n,jprint(params,0));
|
|
||||||
for (i=0; i<n; i++)
|
|
||||||
{
|
|
||||||
if ( musig_parsepubkey(ctx,spk,jitem(params,i)) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing pk"));
|
|
||||||
pubkeys.push_back(spk);
|
|
||||||
}
|
|
||||||
if ( secp256k1_musig_pubkey_combine(ctx,NULL,&combined_pk,pkhash,&pubkeys[0],n) > 0 )
|
|
||||||
{
|
|
||||||
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&combined_pk,SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
|
|
||||||
{
|
|
||||||
for (i=0; i<32; i++)
|
|
||||||
sprintf(&str[i<<1],"%02x",pkhash[i]);
|
|
||||||
str[64] = 0;
|
|
||||||
result.push_back(Pair("pkhash",str));
|
|
||||||
|
|
||||||
for (i=0; i<33; i++)
|
|
||||||
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
|
|
||||||
str[66] = 0;
|
|
||||||
result.push_back(Pair("combined_pk",str));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
return(result);
|
|
||||||
} else return(cclib_error(result,"error serializeing combined_pk"));
|
|
||||||
} else return(cclib_error(result,"error combining pukbeys"));
|
|
||||||
} else return(cclib_error(result,"need pubkeys params"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_session(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
UniValue result(UniValue::VOBJ);
|
||||||
UniValue result(UniValue::VOBJ); int32_t i,n,myind,num,musiglocation; char *pkstr,*pkhashstr,*msgstr; uint8_t session[32],msg[32],pkhash[32],privkey[32],pub33[33]; CPubKey pk; char str[67];
|
return result;
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 5 )
|
|
||||||
{
|
|
||||||
myind = juint(jitem(params,0),0);
|
|
||||||
num = juint(jitem(params,1),0);
|
|
||||||
if ( myind < 0 || myind >= num || num <= 0 )
|
|
||||||
return(cclib_error(result,"illegal myindex and numsigners"));
|
|
||||||
if ( n > 5 )
|
|
||||||
musiglocation = juint(jitem(params,5),0);
|
|
||||||
else if ( n == 5 )
|
|
||||||
musiglocation = 0;
|
|
||||||
//printf("number of params.%i musiglocation.%i\n",n,musiglocation);
|
|
||||||
if ( MUSIG.size() > musiglocation )
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MUSIG.size()-1; i++)
|
|
||||||
musig_infofree(MUSIG[i]);
|
|
||||||
MUSIG.clear();
|
|
||||||
}
|
|
||||||
struct musig_info *temp_musig = musig_infocreate(myind,num);
|
|
||||||
MUSIG.push_back(temp_musig);
|
|
||||||
if ( musig_parsepubkey(ctx,MUSIG[musiglocation]->combined_pk,jitem(params,2)) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing combined_pubkey"));
|
|
||||||
else if ( cclib_parsehash(MUSIG[musiglocation]->pkhash,jitem(params,3),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing pkhash"));
|
|
||||||
else if ( cclib_parsehash(MUSIG[musiglocation]->msg,jitem(params,4),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing msg"));
|
|
||||||
Myprivkey(privkey);
|
|
||||||
GetRandBytes(session,32);
|
|
||||||
/** Initializes a signing session for a signer
|
|
||||||
*
|
|
||||||
* Returns: 1: session is successfully initialized
|
|
||||||
* 0: session could not be initialized: secret key or secret nonce overflow
|
|
||||||
* Args: ctx: pointer to a context object, initialized for signing (cannot
|
|
||||||
* be NULL)
|
|
||||||
* Out: session: the session structure to initialize (cannot be NULL)
|
|
||||||
* signers: an array of signers' data to be initialized. Array length must
|
|
||||||
* equal to `n_signers` (cannot be NULL)
|
|
||||||
* nonce_commitment32: filled with a 32-byte commitment to the generated nonce
|
|
||||||
* (cannot be NULL)
|
|
||||||
* In: session_id32: a *unique* 32-byte ID to assign to this session (cannot be
|
|
||||||
* NULL). If a non-unique session_id32 was given then a partial
|
|
||||||
* signature will LEAK THE SECRET KEY.
|
|
||||||
* msg32: the 32-byte message to be signed. Shouldn't be NULL unless you
|
|
||||||
* require sharing public nonces before the message is known
|
|
||||||
* because it reduces nonce misuse resistance. If NULL, must be
|
|
||||||
* set with `musig_session_set_msg` before signing and verifying.
|
|
||||||
* combined_pk: the combined public key of all signers (cannot be NULL)
|
|
||||||
* pk_hash32: the 32-byte hash of the signers' individual keys (cannot be
|
|
||||||
* NULL)
|
|
||||||
* n_signers: length of signers array. Number of signers participating in
|
|
||||||
* the MuSig. Must be greater than 0 and at most 2^32 - 1.
|
|
||||||
* my_index: index of this signer in the signers array
|
|
||||||
* seckey: the signer's 32-byte secret key (cannot be NULL)
|
|
||||||
*/
|
|
||||||
//fprintf(stderr, "SESSION: struct_size.%li using struct %i\n",MUSIG.size(), musiglocation);
|
|
||||||
if ( secp256k1_musig_session_initialize(ctx,&MUSIG[musiglocation]->session,MUSIG[musiglocation]->signer_data, &MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind * 32],session,MUSIG[musiglocation]->msg,&MUSIG[musiglocation]->combined_pk,MUSIG[musiglocation]->pkhash,MUSIG[musiglocation]->num,MUSIG[musiglocation]->myind,privkey) > 0 )
|
|
||||||
{
|
|
||||||
memset(session,0,sizeof(session));
|
|
||||||
result.push_back(Pair("myind",(int64_t)myind));
|
|
||||||
result.push_back(Pair("numsigners",(int64_t)num));
|
|
||||||
for (i=0; i<32; i++)
|
|
||||||
sprintf(&str[i<<1],"%02x",MUSIG[musiglocation]->nonce_commitments[MUSIG[musiglocation]->myind*32 + i]);
|
|
||||||
str[64] = 0;
|
|
||||||
if ( n == 5 )
|
|
||||||
MUSIG[musiglocation]->numcommits = 1;
|
|
||||||
result.push_back(Pair("commitment",str));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
memset(privkey,0,sizeof(privkey));
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memset(privkey,0,sizeof(privkey));
|
|
||||||
memset(session,0,sizeof(session));
|
|
||||||
return(cclib_error(result,"couldnt initialize session"));
|
|
||||||
}
|
|
||||||
} else return(cclib_error(result,"wrong number of params, need 5: myindex, numsigners, combined_pk, pkhash, msg32"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_commit(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
UniValue result(UniValue::VOBJ);
|
||||||
size_t clen = CPubKey::PUBLIC_KEY_SIZE;
|
return result;
|
||||||
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32]; CPubKey pk; char str[67];
|
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
|
|
||||||
{
|
|
||||||
if ( n > 3 )
|
|
||||||
myind = juint(jitem(params,3),0);
|
|
||||||
else if ( n == 3 )
|
|
||||||
myind = 0;
|
|
||||||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing pkhash"));
|
|
||||||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
|
|
||||||
return(cclib_error(result,"pkhash doesnt match session pkhash"));
|
|
||||||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
|
|
||||||
return(cclib_error(result,"illegal ind for session"));
|
|
||||||
else if ( cclib_parsehash(&MUSIG[myind]->nonce_commitments[ind*32],jitem(params,2),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing commitment"));
|
|
||||||
/** Gets the signer's public nonce given a list of all signers' data with commitments
|
|
||||||
*
|
|
||||||
* Returns: 1: public nonce is written in nonce
|
|
||||||
* 0: signer data is missing commitments or session isn't initialized
|
|
||||||
* for signing
|
|
||||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
|
||||||
* session: the signing session to get the nonce from (cannot be NULL)
|
|
||||||
* signers: an array of signers' data initialized with
|
|
||||||
* `musig_session_initialize`. Array length must equal to
|
|
||||||
* `n_commitments` (cannot be NULL)
|
|
||||||
* Out: nonce: the nonce (cannot be NULL)
|
|
||||||
* In: commitments: array of 32-byte nonce commitments (cannot be NULL)
|
|
||||||
* n_commitments: the length of commitments and signers array. Must be the total
|
|
||||||
* number of signers participating in the MuSig.
|
|
||||||
*/
|
|
||||||
result.push_back(Pair("added_index",ind));
|
|
||||||
//fprintf(stderr, "COMMIT: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
|
|
||||||
MUSIG[myind]->numcommits++;
|
|
||||||
if ( MUSIG[myind]->numcommits >= MUSIG[myind]->num && secp256k1_musig_session_get_public_nonce(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,&MUSIG[myind]->nonces[MUSIG[myind]->myind],MUSIG[myind]->commitment_ptrs,MUSIG[myind]->num) > 0 )
|
|
||||||
{
|
|
||||||
if ( secp256k1_ec_pubkey_serialize(ctx,(uint8_t *)pk.begin(),&clen,&MUSIG[myind]->nonces[MUSIG[myind]->myind],SECP256K1_EC_COMPRESSED) > 0 && clen == 33 )
|
|
||||||
{
|
|
||||||
for (i=0; i<33; i++)
|
|
||||||
sprintf(&str[i<<1],"%02x",((uint8_t *)pk.begin())[i]);
|
|
||||||
str[66] = 0;
|
|
||||||
if ( n == 3 )
|
|
||||||
MUSIG[myind]->numnonces = 1;
|
|
||||||
result.push_back(Pair("myind",MUSIG[myind]->myind));
|
|
||||||
result.push_back(Pair("nonce",str));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
} else return(cclib_error(result,"error serializing nonce (pubkey)"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.push_back(Pair("status","not enough commitments"));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
}
|
|
||||||
return(result);
|
|
||||||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, commitment"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_nonce(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
UniValue result(UniValue::VOBJ);
|
||||||
UniValue result(UniValue::VOBJ); int32_t i,n,ind,myind; uint8_t pkhash[32],psig[32]; CPubKey pk; char str[67];
|
return result;
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
|
|
||||||
{
|
|
||||||
if ( n > 3 )
|
|
||||||
myind = juint(jitem(params,3),0);
|
|
||||||
else if ( n == 3 )
|
|
||||||
myind = 0;
|
|
||||||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing pkhash"));
|
|
||||||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
|
|
||||||
return(cclib_error(result,"pkhash doesnt match session pkhash"));
|
|
||||||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
|
|
||||||
return(cclib_error(result,"illegal ind for session"));
|
|
||||||
else if ( musig_parsepubkey(ctx,MUSIG[myind]->nonces[ind],jitem(params,2)) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing nonce"));
|
|
||||||
result.push_back(Pair("added_index",ind));
|
|
||||||
/** Checks a signer's public nonce against a commitment to said nonce, and update
|
|
||||||
* data structure if they match
|
|
||||||
*
|
|
||||||
* Returns: 1: commitment was valid, data structure updated
|
|
||||||
* 0: commitment was invalid, nothing happened
|
|
||||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
|
||||||
* signer: pointer to the signer data to update (cannot be NULL). Must have
|
|
||||||
* been used with `musig_session_get_public_nonce` or initialized
|
|
||||||
* with `musig_session_initialize_verifier`.
|
|
||||||
* In: nonce: signer's alleged public nonce (cannot be NULL)
|
|
||||||
*/
|
|
||||||
MUSIG[myind]->numnonces++;
|
|
||||||
//fprintf(stderr, "NONCE: struct_size.%li using_struct.%i added_index.%i numnounces.%i num.%i\n",MUSIG.size(), myind, ind, MUSIG[myind]->numnonces, MUSIG[myind]->num);
|
|
||||||
if ( MUSIG[myind]->numnonces < MUSIG[myind]->num )
|
|
||||||
{
|
|
||||||
result.push_back(Pair("status","not enough nonces"));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
for (i=0; i<MUSIG[myind]->num; i++)
|
|
||||||
{
|
|
||||||
if ( secp256k1_musig_set_nonce(ctx,&MUSIG[myind]->signer_data[i],&MUSIG[myind]->nonces[i]) == 0 )
|
|
||||||
return(cclib_error(result,"error setting nonce"));
|
|
||||||
}
|
|
||||||
/** Updates a session with the combined public nonce of all signers. The combined
|
|
||||||
* public nonce is the sum of every signer's public nonce.
|
|
||||||
*
|
|
||||||
* Returns: 1: nonces are successfully combined
|
|
||||||
* 0: a signer's nonce is missing
|
|
||||||
* Args: ctx: pointer to a context object (cannot be NULL)
|
|
||||||
* session: session to update with the combined public nonce (cannot be
|
|
||||||
* NULL)
|
|
||||||
* signers: an array of signers' data, which must have had public nonces
|
|
||||||
* set with `musig_set_nonce`. Array length must equal to `n_signers`
|
|
||||||
* (cannot be NULL)
|
|
||||||
* n_signers: the length of the signers array. Must be the total number of
|
|
||||||
* signers participating in the MuSig.
|
|
||||||
* Out: nonce_is_negated: a pointer to an integer that indicates if the combined
|
|
||||||
* public nonce had to be negated.
|
|
||||||
* adaptor: point to add to the combined public nonce. If NULL, nothing is
|
|
||||||
* added to the combined nonce.
|
|
||||||
*/
|
|
||||||
if ( secp256k1_musig_session_combine_nonces(ctx,&MUSIG[myind]->session,MUSIG[myind]->signer_data,MUSIG[myind]->num,NULL,NULL) > 0 )
|
|
||||||
{
|
|
||||||
if ( secp256k1_musig_partial_sign(ctx,&MUSIG[myind]->session,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
|
|
||||||
{
|
|
||||||
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
|
|
||||||
{
|
|
||||||
for (i=0; i<32; i++)
|
|
||||||
sprintf(&str[i<<1],"%02x",psig[i]);
|
|
||||||
str[64] = 0;
|
|
||||||
result.push_back(Pair("myind",MUSIG[myind]->myind));
|
|
||||||
result.push_back(Pair("partialsig",str));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
if ( n == 3 )
|
|
||||||
MUSIG[myind]->numpartials = 1;
|
|
||||||
return(result);
|
|
||||||
} else return(cclib_error(result,"error serializing partial sig"));
|
|
||||||
} else return(cclib_error(result,"error making partial sig"));
|
|
||||||
} else return(cclib_error(result,"error combining nonces"));
|
|
||||||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, nonce"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_partialsig(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
UniValue result(UniValue::VOBJ);
|
||||||
UniValue result(UniValue::VOBJ); int32_t i,ind,n,myind; uint8_t pkhash[32],psig[32],out64[64]; char str[129]; secp256k1_schnorrsig sig;
|
return result;
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) >= 3 )
|
|
||||||
{
|
|
||||||
if ( n > 3 )
|
|
||||||
myind = juint(jitem(params,3),0);
|
|
||||||
else if ( n == 3 )
|
|
||||||
myind = 0;
|
|
||||||
if ( cclib_parsehash(pkhash,jitem(params,0),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing pkhash"));
|
|
||||||
else if ( memcmp(MUSIG[myind]->pkhash,pkhash,32) != 0 )
|
|
||||||
return(cclib_error(result,"pkhash doesnt match session pkhash"));
|
|
||||||
else if ( (ind= juint(jitem(params,1),0)) < 0 || ind >= MUSIG[myind]->num )
|
|
||||||
return(cclib_error(result,"illegal ind for session"));
|
|
||||||
else if ( cclib_parsehash(psig,jitem(params,2),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing psig"));
|
|
||||||
else if ( secp256k1_musig_partial_signature_parse(ctx,&MUSIG[myind]->partial_sig[ind],psig) == 0 )
|
|
||||||
return(cclib_error(result,"error parsing partialsig"));
|
|
||||||
result.push_back(Pair("added_index",ind));
|
|
||||||
//fprintf(stderr, "SIG: struct_size.%li using_struct.%i added_index.%i\n",MUSIG.size(), myind, ind);
|
|
||||||
MUSIG[myind]->numpartials++;
|
|
||||||
if ( MUSIG[myind]->numpartials >= MUSIG[myind]->num && secp256k1_musig_partial_sig_combine(ctx,&MUSIG[myind]->session,&sig,MUSIG[myind]->partial_sig,MUSIG[myind]->num) > 0 )
|
|
||||||
{
|
|
||||||
if ( secp256k1_schnorrsig_serialize(ctx,out64,&sig) > 0 )
|
|
||||||
{
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
for (i=0; i<64; i++)
|
|
||||||
sprintf(&str[i<<1],"%02x",out64[i]);
|
|
||||||
str[128] = 0;
|
|
||||||
result.push_back(Pair("combinedsig",str));
|
|
||||||
} else return(cclib_error(result,"error serializing combinedsig"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( secp256k1_musig_partial_signature_serialize(ctx,psig,&MUSIG[myind]->partial_sig[MUSIG[myind]->myind]) > 0 )
|
|
||||||
{
|
|
||||||
result.push_back(Pair("myind",ind));
|
|
||||||
for (i=0; i<32; i++)
|
|
||||||
sprintf(&str[i<<1],"%02x",psig[i]);
|
|
||||||
str[64] = 0;
|
|
||||||
result.push_back(Pair("partialsig",str));
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
result.push_back(Pair("status","need more partialsigs"));
|
|
||||||
} else return(cclib_error(result,"error generating my partialsig"));
|
|
||||||
}
|
|
||||||
return(result);
|
|
||||||
} else return(cclib_error(result,"wrong number of params, need 3: pkhash, ind, partialsig"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//int testmain(void);
|
//int testmain(void);
|
||||||
UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_verify(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
UniValue result(UniValue::VOBJ);
|
||||||
UniValue result(UniValue::VOBJ); int32_t i,n; uint8_t msg[32],musig64[64]; secp256k1_pubkey combined_pk; secp256k1_schnorrsig musig; char str[129];
|
return result;
|
||||||
//testmain();
|
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) == 3 )
|
|
||||||
{
|
|
||||||
if ( cclib_parsehash(msg,jitem(params,0),32) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing pkhash"));
|
|
||||||
else if ( musig_parsepubkey(ctx,combined_pk,jitem(params,1)) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing combined_pk"));
|
|
||||||
else if ( cclib_parsehash(musig64,jitem(params,2),64) < 0 )
|
|
||||||
return(cclib_error(result,"error parsing musig64"));
|
|
||||||
for (i=0; i<32; i++)
|
|
||||||
sprintf(&str[i*2],"%02x",msg[i]);
|
|
||||||
str[64] = 0;
|
|
||||||
result.push_back(Pair("msg",str));
|
|
||||||
result.push_back(Pair("combined_pk",jstr(jitem(params,1),0)));
|
|
||||||
for (i=0; i<64; i++)
|
|
||||||
sprintf(&str[i*2],"%02x",musig64[i]);
|
|
||||||
str[128] = 0;
|
|
||||||
result.push_back(Pair("combinedsig",str));
|
|
||||||
if ( secp256k1_schnorrsig_parse(ctx,&musig,&musig64[0]) > 0 )
|
|
||||||
{
|
|
||||||
if ( secp256k1_schnorrsig_verify(ctx,&musig,msg,&combined_pk) > 0 )
|
|
||||||
{
|
|
||||||
result.push_back(Pair("result","success"));
|
|
||||||
return(result);
|
|
||||||
} else return(cclib_error(result,"musig didnt verify"));
|
|
||||||
} else return(cclib_error(result,"couldnt parse musig64"));
|
|
||||||
} else return(cclib_error(result,"wrong number of params, need 3: msg, combined_pk, combinedsig"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers for rpc calls that generate/validate onchain tx
|
|
||||||
|
|
||||||
UniValue musig_rawtxresult(UniValue &result,std::string rawtx)
|
UniValue musig_rawtxresult(UniValue &result,std::string rawtx)
|
||||||
{
|
{
|
||||||
CTransaction tx;
|
UniValue result(UniValue::VOBJ);
|
||||||
if ( rawtx.size() > 0 )
|
return result;
|
||||||
{
|
|
||||||
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 musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_send(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight());
|
UniValue result(UniValue::VOBJ);
|
||||||
UniValue result(UniValue::VOBJ); int32_t n; char *hexstr; std::string rawtx; int64_t amount; CPubKey musigpk,mypk;
|
return result;
|
||||||
if ( txfee == 0 )
|
|
||||||
txfee = MUSIG_TXFEE;
|
|
||||||
mypk = pubkey2pk(Mypubkey());
|
|
||||||
musigpk = GetUnspendable(cp,0);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
|
||||||
{
|
|
||||||
if ( n == 2 && (hexstr= jstr(jitem(params,0),0)) != 0 && is_hexstr(hexstr,0) == 66 )
|
|
||||||
{
|
|
||||||
CPubKey pk(ParseHex(hexstr));
|
|
||||||
amount = jdouble(jitem(params,1),0) * COIN + 0.0000000049;
|
|
||||||
if ( amount >= 3*txfee && AddNormalinputs(mtx,mypk,amount+2*txfee,64) >= amount+2*txfee )
|
|
||||||
{
|
|
||||||
mtx.vout.push_back(MakeCC1vout(cp->evalcode,amount+txfee,musigpk));
|
|
||||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_sendopret('x',pk));
|
|
||||||
return(musig_rawtxresult(result,rawtx));
|
|
||||||
} else return(cclib_error(result,"couldnt find funds or less than 0.0003"));
|
|
||||||
} else return(cclib_error(result,"must have 2 params: pk, amount"));
|
|
||||||
} else return(cclib_error(result,"not enough parameters"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
UniValue musig_spend(uint64_t txfee,struct CCcontract_info *cp,cJSON *params)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
UniValue result(UniValue::VOBJ);
|
||||||
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), hush_nextheight());
|
return result;
|
||||||
UniValue result(UniValue::VOBJ); std::string rawtx; CPubKey mypk,pk; secp256k1_pubkey combined_pk; char *scriptstr,*musigstr; uint8_t msg[32]; CTransaction vintx; uint256 prevhash,hashBlock; int32_t i,n,numvouts; char str[129]; CTxOut vout; secp256k1_schnorrsig musig;
|
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( params != 0 && (n= cJSON_GetArraySize(params)) > 0 )
|
|
||||||
{
|
|
||||||
if ( n == 3 )
|
|
||||||
{
|
|
||||||
prevhash = juint256(jitem(params,0));
|
|
||||||
scriptstr = jstr(jitem(params,1),0);
|
|
||||||
musigstr = jstr(jitem(params,2),0);
|
|
||||||
if ( is_hexstr(scriptstr,0) != 0 && is_hexstr(musigstr,0) == 128 )
|
|
||||||
{
|
|
||||||
if ( txfee == 0 )
|
|
||||||
txfee = MUSIG_TXFEE;
|
|
||||||
mypk = pubkey2pk(Mypubkey());
|
|
||||||
std::vector<uint8_t> musig64(ParseHex(musigstr));
|
|
||||||
CScript scriptPubKey;
|
|
||||||
scriptPubKey.resize(strlen(scriptstr)/2);
|
|
||||||
decode_hex(&scriptPubKey[0],strlen(scriptstr)/2,scriptstr);
|
|
||||||
if ( myGetTransaction(prevhash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
|
|
||||||
{
|
|
||||||
vout.nValue = vintx.vout[0].nValue - txfee;
|
|
||||||
vout.scriptPubKey = scriptPubKey;
|
|
||||||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
|
|
||||||
{
|
|
||||||
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
|
|
||||||
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
|
|
||||||
{
|
|
||||||
musig_prevoutmsg(msg,prevhash,vout.scriptPubKey);
|
|
||||||
{
|
|
||||||
for (i=0; i<32; i++)
|
|
||||||
sprintf(&str[i*2],"%02x",msg[i]);
|
|
||||||
str[64] = 0;
|
|
||||||
result.push_back(Pair("msg",str));
|
|
||||||
for (i=0; i<33; i++)
|
|
||||||
sprintf(&str[i*2],"%02x",((uint8_t *)pk.begin())[i]);
|
|
||||||
str[66] = 0;
|
|
||||||
result.push_back(Pair("combined_pk",str));
|
|
||||||
for (i=0; i<64; i++)
|
|
||||||
sprintf(&str[i*2],"%02x",musig64[i]);
|
|
||||||
str[128] = 0;
|
|
||||||
result.push_back(Pair("combinedsig",str));
|
|
||||||
}
|
|
||||||
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) )
|
|
||||||
{
|
|
||||||
return(cclib_error(result,"musig didnt validate"));
|
|
||||||
}
|
|
||||||
mtx.vin.push_back(CTxIn(prevhash,MUSIG_PREVN));
|
|
||||||
mtx.vout.push_back(vout);
|
|
||||||
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,musig_spendopret('y',pk,musig64));
|
|
||||||
return(musig_rawtxresult(result,rawtx));
|
|
||||||
} else return(cclib_error(result,"couldnt parse pk or musig"));
|
|
||||||
} else return(cclib_error(result,"couldnt decode send opret"));
|
|
||||||
} else return(cclib_error(result,"couldnt find vin0"));
|
|
||||||
} else return(cclib_error(result,"script or musig is not hex"));
|
|
||||||
} else return(cclib_error(result,"need to have exactly 3 params sendtxid, scriptPubKey, musig"));
|
|
||||||
} else return(cclib_error(result,"params parse error"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
bool musig_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx)
|
||||||
{
|
{
|
||||||
static secp256k1_context *ctx;
|
return false;
|
||||||
secp256k1_pubkey combined_pk; CPubKey pk,checkpk; secp256k1_schnorrsig musig; uint256 hashBlock; CTransaction vintx; int32_t numvouts; std::vector<uint8_t> musig64; uint8_t msg[32];
|
|
||||||
if ( ctx == 0 )
|
|
||||||
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
|
|
||||||
if ( tx.vout.size() != 2 )
|
|
||||||
return eval->Invalid("numvouts != 2");
|
|
||||||
else if ( tx.vin.size() != 1 )
|
|
||||||
return eval->Invalid("numvins != 1");
|
|
||||||
else if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
|
|
||||||
return eval->Invalid("illegal normal vin0");
|
|
||||||
else if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,hashBlock) != 0 && (numvouts= vintx.vout.size()) > 1 )
|
|
||||||
{
|
|
||||||
if ( musig_sendopretdecode(pk,vintx.vout[numvouts-1].scriptPubKey) == 'x' )
|
|
||||||
{
|
|
||||||
if ( musig_spendopretdecode(checkpk,musig64,tx.vout[tx.vout.size()-1].scriptPubKey) == 'y' )
|
|
||||||
{
|
|
||||||
if ( pk == checkpk )
|
|
||||||
{
|
|
||||||
if ( secp256k1_schnorrsig_parse((const secp256k1_context *)ctx,&musig,(const uint8_t *)&musig64[0]) > 0 &&
|
|
||||||
secp256k1_ec_pubkey_parse(ctx,&combined_pk,pk.begin(),33) > 0 )
|
|
||||||
{
|
|
||||||
musig_prevoutmsg(msg,tx.vin[0].prevout.hash,tx.vout[0].scriptPubKey);
|
|
||||||
if ( !secp256k1_schnorrsig_verify((const secp256k1_context *)ctx,&musig,(const uint8_t *)msg,(const secp256k1_pubkey *)&combined_pk) )
|
|
||||||
return eval->Invalid("failed schnorrsig_verify");
|
|
||||||
else return(true);
|
|
||||||
} else return eval->Invalid("couldnt parse pk or musig");
|
|
||||||
} else return eval->Invalid("combined_pk didnt match send opret");
|
|
||||||
} else return eval->Invalid("failed decode musig spendopret");
|
|
||||||
} else return eval->Invalid("couldnt decode send opret");
|
|
||||||
} else return eval->Invalid("couldnt find vin0 tx");
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user