/****************************************************************************** * Copyright © 2014-2015 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. * * * ******************************************************************************/ #ifdef later #define BUNDLED #define PLUGINSTR "pangea" #define PLUGNAME(NAME) pangea ## NAME #define STRUCTNAME struct PLUGNAME(_info) #define STRINGIFY(NAME) #NAME #define PLUGIN_EXTRASIZE sizeof(STRUCTNAME) #include #define DEFINES_ONLY //#include "../../utils/huffstream.c" #include "../../common/hostnet777.c" #include "../../includes/cJSON.h" #include "../../agents/plugin777.c" #undef DEFINES_ONLY #include "../InstantDEX/InstantDEX_quote.h" #include "../includes/curve25519.h" #define _PANGEA_MAXTHREADS 9 #define PANGEA_MINRAKE_MILLIS 5 #define PANGEA_USERTIMEOUT 60 #define PANGEA_MAX_HOSTRAKE 5 #define PANGEA_BTCMAXRAKE (SATOSHIDEN / 100) #define PANGEA_MAXRAKE (3 * SATOSHIDEN) #define PANGEA_HANDGAP 30 #define PANGEA_PAUSE 5 struct pangea_info { uint32_t timestamp,numaddrs,minbuyin,maxbuyin; int64_t balances[CARDS777_MAXPLAYERS]; uint8_t isbot[CARDS777_MAXPLAYERS]; bits256 playerpubs[CARDS777_MAXPLAYERS]; uint64_t basebits,bigblind,ante,addrs[CARDS777_MAXPLAYERS],active[CARDS777_MAXPLAYERS],tableid; char btcpubkeystr[67],wipstr[64],coinstr[16],multisigaddr[64],scriptPubKey[128],redeemScript[4096]; uint8_t addrtype,p2shtype,wiftype,btcpub[33]; int32_t myslot,myind,numactive,buyinvouts[CARDS777_MAXPLAYERS]; uint64_t buyinamounts[CARDS777_MAXPLAYERS]; char buyintxids[CARDS777_MAXPLAYERS][128],coinaddrs[CARDS777_MAXPLAYERS][67],btcpubkeys[CARDS777_MAXPLAYERS][67]; struct pangea_thread *tp; struct cards777_privdata *priv; struct cards777_pubdata *dp; } *TABLES[100]; //./BitcoinDarkd SuperNET '{"agent":"InstantDEX","method":"orderbook","exchange":"active","base":"NXT","rel":"BTC"}' // ./SNapi "{\"agent\":\"InstantDEX\",\"method\":\"orderbook\",\"exchange\":\"pangea\",\"base\":\"NXT\"}" // ./SNapi "{\"agent\":\"InstantDEX\",\"method\":\"placebid\",\"exchange\":\"pangea\",\"base\":\"NXT\"}" struct pangea_thread { union hostnet777 hn; uint64_t nxt64bits; int32_t threadid,ishost,M,N,numcards; } *THREADS[_PANGEA_MAXTHREADS]; int32_t PANGEA_MAXTHREADS = 0; int32_t Showmode,Autofold; //uint64_t Pangea_waiting,Pangea_userinput_betsize; uint32_t Pangea_userinput_starttime; int32_t Pangea_userinput_cardi; char Pangea_userinput[128]; char *clonestr(char *); uint64_t stringbits(char *str); uint32_t set_handstr(char *handstr,uint8_t cards[7],int32_t verbose); int32_t cardstr(char *cardstr,uint8_t card); int32_t init_hexbytes_noT(char *hexbytes,uint8_t *message,long len); bits256 issue_getpubkey(int32_t *haspubkeyp,char *acct); uint64_t set_account_NXTSECRET(void *myprivkey,void *mypubkey,char *NXTacct,char *NXTaddr,char *secret,int32_t max,cJSON *argjson,char *coinstr,char *serverport,char *userpass); int32_t pangea_anotherhand(union hostnet777 *hn,struct cards777_pubdata *dp,int32_t sleepflag); void pangea_clearhand(struct cards777_pubdata *dp,struct cards777_handinfo *hand,struct cards777_privdata *priv); void pangea_create_newtable(char *retbuf,struct pangea_info *sp,struct cards777_pubdata *dp,uint64_t *isbot); #define PANGEA_COMMANDS "start", "newtable", "status", "turn" char *PLUGNAME(_methods)[] = { PANGEA_COMMANDS }; char *PLUGNAME(_pubmethods)[] = { PANGEA_COMMANDS }; char *PLUGNAME(_authmethods)[] = { PANGEA_COMMANDS }; uint64_t PLUGNAME(_register)(struct plugin_info *plugin,STRUCTNAME *data,cJSON *argjson) { uint64_t disableflags = 0; return(disableflags); // set bits corresponding to array position in _methods[] } int32_t PLUGNAME(_shutdown)(struct plugin_info *plugin,int32_t retcode) { if ( retcode == 0 ) // this means parent process died, otherwise _process_json returned negative value { } return(retcode); } int32_t pangea_search(struct pangea_info *sp,uint64_t nxt64bits) { int32_t i; for (i=0; inumactive; i++) if ( sp->active[i] == nxt64bits ) return(i); for (i=0; inumactive; i++) PostMessage("%llu ",(long long)sp->active[i]); PostMessage("active[]\n"); for (i=0; inumaddrs; i++) PostMessage("%llu ",(long long)sp->addrs[i]); PostMessage("addrs[]\n"); PostMessage("pangea_search: slot.%d ind.%d cant find %llu in active[%d]\n",sp->myslot,sp->myind,(long long)nxt64bits,sp->numactive); return(-1); } int32_t pangea_tableaddr(struct cards777_pubdata *dp,uint64_t destbits) { int32_t i; struct pangea_info *sp; if ( dp != 0 && (sp= dp->table) != 0 ) { for (i=0; inumaddrs; i++) if ( sp->addrs[i] == destbits ) return(i); } return(-1); } int32_t pangea_slotA(struct pangea_info *sp) { return(0); } int32_t pangea_slotB(struct pangea_info *sp) { uint64_t nxt64bits; nxt64bits = sp->active[1]; return(pangea_search(sp,nxt64bits)); } int32_t pangea_slot(struct pangea_info *sp,int32_t ind) { return(pangea_tableaddr(sp->dp,sp->active[ind])); } int32_t pangea_ind(struct pangea_info *sp,int32_t slot) { return(pangea_search(sp,sp->addrs[slot])); } int32_t pangea_lastnode(struct pangea_info *sp) { return(pangea_search(sp,sp->active[sp->numactive-1])); } int32_t pangea_nextnode(struct pangea_info *sp) { if ( sp->myind < sp->numactive-1 ) return(sp->myind + 1); else { PostMessage("pangea_nextnode: no next node from last node slot.%d ind.%d of numaddrs.%d numactive.%d\n",sp->myslot,sp->myind,sp->numaddrs,sp->numactive); return(-1); } } int32_t pangea_prevnode(struct pangea_info *sp) { if ( sp->myind > 0 ) return(sp->myind - 1); else { PostMessage("pangea_prevnode: no prev node from node slot %d, ind.%d\n",sp->myslot,sp->myind); return(-1); } } int32_t pangea_neworder(struct cards777_pubdata *dp,struct pangea_info *sp,uint64_t *active,int32_t numactive) { int32_t slots[CARDS777_MAXPLAYERS],i; if ( active == 0 ) active = sp->active, numactive = sp->numactive; memset(slots,0,sizeof(slots)); if ( active[0] != sp->addrs[0] ) { PostMessage("pangea_neworder: neworder requires host nodeA to be first active node\n"); return(-1); } slots[0] = 0; for (i=1; inumaddrs); return(-1); } } for (i=0; iactive[i] = active[i]; //PostMessage("%llu ",(long long)sp->active[i]); } sp->numactive = dp->N = numactive; dp->M = (numactive >> 1) + 1; sp->myind = pangea_ind(sp,sp->myslot); //PostMessage("T%d neworder.%d -> M.%d N.%d ind.%d\n",sp->myslot,sp->numactive,dp->M,dp->N,sp->myind); return(numactive); } int32_t pangea_inactivate(struct cards777_pubdata *dp,struct pangea_info *sp,uint64_t nxt64bits) { int32_t i,n; uint64_t active[CARDS777_MAXPLAYERS]; for (i=n=0; inumactive; i++) { if ( sp->active[i] == nxt64bits ) continue; active[n++] = sp->active[i]; } if ( n != sp->numactive-1 ) PostMessage("pangea_inactivate: cant find %llu\n",(long long)nxt64bits); PostMessage("T%d inactivate %llu n.%d\n",sp->myslot,(long long)nxt64bits,n); pangea_neworder(dp,sp,active,n); return(n); } int32_t pangea_addplayer(struct cards777_pubdata *dp,struct pangea_info *sp,bits256 clientpub) { int32_t i,n,openslot = -1; uint64_t nxt64bits = acct777_nxt64bits(clientpub); for (i=n=0; inumaddrs; i++) { if ( sp->addrs[i] == nxt64bits ) { PostMessage("pangea_addplayer: player %llu already in addrs[%d]\n",(long long)nxt64bits,i); return(-1); } if ( sp->balances[i] <= 0 ) openslot = i; } if ( openslot < 0 || sp->numactive >= sp->numaddrs-1 ) { PostMessage("pangea_addplayer: no room to add %llu\n",(long long)nxt64bits); return(-1); } dp->readymask &= ~(1 << openslot); sp->addrs[openslot] = nxt64bits; sp->playerpubs[openslot] = clientpub; sp->active[sp->numactive++] = nxt64bits; if ( sp->myslot == 0 ) { uint64_t isbot[CARDS777_MAXPLAYERS]; char *retbuf = malloc(65536); if ( retbuf != 0 ) { hostnet777_replace(sp->tp->hn.server,clientpub,openslot); for (i=0; inumactive; i++) isbot[i] = sp->isbot[i]; pangea_create_newtable(retbuf,sp,dp,isbot); hostnet777_msg(nxt64bits,clientpub,&sp->tp->hn,0,retbuf,(int32_t)strlen(retbuf)+1); free(retbuf); } } pangea_neworder(dp,sp,0,0); return(n); } void pangea_sendcmd(char *hex,union hostnet777 *hn,char *cmdstr,int32_t destplayer,uint8_t *data,int32_t datalen,int32_t cardi,int32_t turni) { int32_t n,hexlen,blindflag = 0; uint64_t destbits; bits256 destpub; cJSON *json; char hoststr[1024]; struct pangea_info *sp; struct cards777_pubdata *dp = hn->client->H.pubdata; hoststr[0] = 0; sp = dp->table; sprintf(hex,"{\"cmd\":\"%s\",\"millitime\":\"%lld\",\"turni\":%d,\"myslot\":%d,\"myind\":%d,\"cardi\":%d,\"dest\":%d,\"sender\":\"%llu\",\"timestamp\":\"%lu\",\"n\":%u,%s\"data\":\"",cmdstr,(long long)hostnet777_convmT(&hn->client->H.mT,0),turni,hn->client->H.slot,pangea_ind(dp->table,hn->client->H.slot),cardi,destplayer,(long long)hn->client->H.nxt64bits,(long)time(NULL),datalen,hoststr); n = (int32_t)strlen(hex); if ( strcmp(cmdstr,"preflop") == 0 ) { memcpy(&hex[n],data,datalen+1); hexlen = (int32_t)strlen(hex)+1; PostMessage("P%d HEX.[] hexlen.%d n.%d\n",hn->server->H.slot,hexlen,datalen); } else if ( data != 0 && datalen != 0 ) init_hexbytes_noT(&hex[n],data,datalen); strcat(hex,"\"}"); if ( (json= cJSON_Parse(hex)) == 0 ) { PostMessage("error creating json\n"); return; } free_json(json); hexlen = (int32_t)strlen(hex)+1; //PostMessage("HEX.[%s] hexlen.%d n.%d\n",hex,hexlen,datalen); if ( destplayer < 0 )//|| ((1LL << destplayer) & dp->pmworks) == 0 ) { destbits = 0; memset(destpub.bytes,0,sizeof(destpub)); //PostMessage("T%d broadcasts %d\n",hn->client->H.slot,hexlen); } else { destpub = sp->playerpubs[pangea_slot(sp,destplayer)]; destbits = acct777_nxt64bits(destpub); //PostMessage("T%d sends %d to dest.%d\n",hn->client->H.slot,hexlen,destplayer); } hostnet777_msg(destbits,destpub,hn,blindflag,hex,hexlen); } #include "pangeafunds.c" bits256 pangea_destpub(uint64_t destbits) { int32_t i,haspubkey; bits256 destpub; char destNXT[64]; memset(destpub.bytes,0,sizeof(destpub)); for (i=0; itp->nxt64bits == destbits ) { destpub = TABLES[i]->tp->hn.client->H.pubkey; break; } if ( i == sizeof(TABLES)/sizeof(*TABLES) ) { expand_nxt64bits(destNXT,destbits); destpub = issue_getpubkey(&haspubkey,destNXT); } return(destpub); } struct pangea_info *pangea_find(uint64_t tableid,int32_t threadid) { int32_t i; for (i=0; itableid && (threadid < 0 || TABLES[i]->tp->threadid == threadid) ) return(TABLES[i]); return(0); } struct pangea_info *pangea_find64(uint64_t tableid,uint64_t nxt64bits) { int32_t i,j; for (i=0; itableid) && TABLES[i]->tp != 0 ) { for (j=0; jnumaddrs; j++) { if ( TABLES[i]->addrs[j] == nxt64bits ) return(TABLES[i]); } } } return(0); } void pangea_free(struct pangea_info *sp) { int32_t i; for (i=0; itableid); free(sp); } void pangea_clearhand(struct cards777_pubdata *dp,struct cards777_handinfo *hand,struct cards777_privdata *priv) { bits256 *final,*cardpubs; int32_t i; final = hand->final, cardpubs = hand->cardpubs; memset(hand,0,sizeof(*hand)); hand->final = final, hand->cardpubs = cardpubs; memset(final,0,sizeof(*final) * dp->N * dp->numcards); memset(cardpubs,0,sizeof(*cardpubs) * (1 + dp->numcards)); for (i=0; i<5; i++) hand->community[i] = 0xff; memset(hand->hands,0xff,sizeof(hand->hands)); priv->hole[0] = priv->hole[1] = priv->cardis[0] = priv->cardis[1] = 0xff; memset(priv->holecards,0,sizeof(priv->holecards)); } void pangea_sendnewdeck(union hostnet777 *hn,struct cards777_pubdata *dp) { int32_t hexlen; bits256 destpub; hexlen = (int32_t)strlen(dp->newhand)+1; memset(destpub.bytes,0,sizeof(destpub)); hostnet777_msg(0,destpub,hn,0,dp->newhand,hexlen); dp->hand.startdecktime = (uint32_t)time(NULL); PostMessage("pangea_sendnewdeck new deck at %u\n",dp->hand.startdecktime); } int32_t pangea_newdeck(union hostnet777 *src) { uint8_t data[(CARDS777_MAXCARDS + 1) * sizeof(bits256)]; struct cards777_pubdata *dp; struct cards777_privdata *priv; int32_t i,n,m,len; bits256 playerpubs[CARDS777_MAXPLAYERS]; struct pangea_info *sp; uint64_t removelist[CARDS777_MAXPLAYERS]; cJSON *array; char *str; dp = src->client->H.pubdata, sp = dp->table; priv = src->client->H.privdata; pangea_clearhand(dp,&dp->hand,priv); for (i=m=0; iN; i++) { if ( sp->balances[pangea_slot(sp,i)] <= 0 ) removelist[m++] = sp->addrs[pangea_slot(sp,i)]; } if ( 0 && m > 0 ) { for (i=0; itable,0,0); array = cJSON_CreateArray(); for (i=0; iN; i++) { playerpubs[i] = sp->playerpubs[pangea_slot(sp,i)]; jaddi64bits(array,sp->active[i]); } str = jprint(array,1); dp->hand.checkprod = dp->hand.cardpubs[dp->numcards] = cards777_initdeck(priv->outcards,dp->hand.cardpubs,dp->numcards,dp->N,playerpubs,0); len = (dp->numcards + 1) * sizeof(bits256); sprintf(dp->newhand,"{\"cmd\":\"%s\",\"millitime\":\"%lld\",\"active\":%s,\"sender\":\"%llu\",\"timestamp\":\"%lu\",\"n\":%u,\"data\":\"","newhand",(long long)hostnet777_convmT(&src->server->H.mT,0),str,(long long)src->client->H.nxt64bits,(long)time(NULL),len); free(str); n = (int32_t)strlen(dp->newhand); memcpy(data,dp->hand.cardpubs,len); init_hexbytes_noT(&dp->newhand[n],data,len); strcat(dp->newhand,"\"}"); pangea_sendnewdeck(src,dp); PostMessage("host sends NEWDECK checkprod.%llx numhands.%d\n",(long long)dp->hand.checkprod.txid,dp->numhands); return(0); } int32_t pangea_anotherhand(union hostnet777 *hn,struct cards777_pubdata *dp,int32_t sleepflag) { int32_t i,n,activej = -1; uint64_t total = 0; struct pangea_info *sp = dp->table; for (i=n=0; inumaddrs; i++) { total += sp->balances[i]; PostMessage("(p%d %.8f) ",i,dstr(sp->balances[i])); if ( sp->balances[i] != 0 ) { if ( activej < 0 ) activej = i; n++; } } PostMessage("balances %.8f [%.8f]\n",dstr(total),dstr(total + dp->hostrake + dp->pangearake)); if ( n == 1 ) { PostMessage("Only player.%d left with %.8f | get sigs and cashout after numhands.%d\n",activej,dstr(sp->balances[pangea_slot(sp,activej)]),dp->numhands); msleep(60000); return(1); } else { if ( sleepflag != 0 ) msleep(sleepflag * 1000); //dp->hand.betstarted = 0; pangea_newdeck(hn); if ( sleepflag != 0 ) msleep(sleepflag * 1000); } return(n); } int32_t pangea_newhand(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { char hex[1024]; int32_t handid,m,i; uint64_t active[CARDS777_MAXPLAYERS]; cJSON *array; struct pangea_info *sp = dp->table; if ( data == 0 || datalen != (dp->numcards + 1) * sizeof(bits256) ) { PostMessage("pangea_newhand invalid datalen.%d vs %ld\n",datalen,(long)((dp->numcards + 1) * sizeof(bits256))); return(-1); } if ( hn->server->H.slot != 0 ) { pangea_clearhand(dp,&dp->hand,priv); if ( (array= jarray(&m,json,"active")) != 0 ) { //PostMessage("T%d (%s)\n",sp->myslot,jprint(array,0)); for (i=0; itable,active,m); } else pangea_neworder(dp,dp->table,0,0); } dp->button = (dp->numhands++ % dp->N); memcpy(dp->hand.cardpubs,data,(dp->numcards + 1) * sizeof(bits256)); PostMessage("player.%d NEWHAND.%llx received numhands.%d button.%d cardi.%d | dp->N %d\n",hn->client->H.slot,(long long)dp->hand.cardpubs[dp->numcards].txid,dp->numhands,dp->button,dp->hand.cardi,dp->N); dp->hand.checkprod = cards777_pubkeys(dp->hand.cardpubs,dp->numcards,dp->hand.cardpubs[dp->numcards]); memset(dp->summary,0,sizeof(dp->summary)); dp->summaries = dp->mismatches = dp->summarysize = 0; handid = dp->numhands - 1; if ( sp->myind >= 0 ) { pangea_summary(hn,dp,CARDS777_START,&handid,sizeof(handid),dp->hand.cardpubs[0].bytes,sizeof(bits256)*(dp->numcards+1)); pangea_sendcmd(hex,hn,"gotdeck",-1,dp->hand.checkprod.bytes,sizeof(uint64_t),dp->hand.cardi,dp->hand.userinput_starttime); } return(0); } void pangea_checkstart(union hostnet777 *hn,struct cards777_pubdata *dp,struct cards777_privdata *priv) { int32_t i; if ( dp->hand.checkprod.txid != 0 && dp->newhand[0] != 0 && dp->hand.encodestarted == 0 ) { for (i=0; iN; i++) { if ( dp->hand.othercardpubs[i] != dp->hand.checkprod.txid ) break; } if ( i == dp->N ) { if ( PANGEA_PAUSE > 0 ) msleep(PANGEA_PAUSE * 1000); dp->hand.encodestarted = (uint32_t)time(NULL); PostMessage("SERVERSTATE issues encoded %llx\n",(long long)dp->hand.checkprod.txid); pangea_sendcmd(dp->newhand,hn,"encoded",pangea_slotB(dp->table),priv->outcards[0].bytes,sizeof(bits256)*dp->N*dp->numcards,dp->N*dp->numcards,-1); } } } int32_t pangea_gotdeck(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { int32_t i,slot; uint64_t total = 0; struct pangea_info *sp = dp->table; dp->hand.othercardpubs[senderind] = *(uint64_t *)data; if ( Debuglevel > 2 ) { for (i=0; iN; i++) { slot = pangea_slot(sp,i); total += sp->balances[slot]; PostMessage("(p%d %.8f) ",i,dstr(sp->balances[slot])); } PostMessage("balances %.8f [%.8f] | ",dstr(total),dstr(total + dp->hostrake + dp->pangearake)); PostMessage("player.%d pangea_gotdeck from P.%d otherpubs.%llx\n",hn->client->H.slot,senderind,(long long)dp->hand.othercardpubs[senderind]); } pangea_checkstart(hn,dp,priv); return(0); } int32_t pangea_ready(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { int32_t create_MofN(uint8_t addrtype,char *redeemScript,char *scriptPubKey,char *p2shaddr,char *pubkeys[],int32_t M,int32_t N); char hex[4096],hexstr[67],*pubkeys[CARDS777_MAXPLAYERS]; struct pangea_info *sp = dp->table; uint8_t addrtype,p2shtype; int32_t i,slot,retval = -1; slot = pangea_slot(sp,senderind); dp->readymask |= (1 << slot); addrtype = coin777_addrtype(&p2shtype,dp->coinstr); if ( datalen == 33 ) { init_hexbytes_noT(hexstr,data,datalen); strcpy(sp->btcpubkeys[slot],hexstr); btc_coinaddr(sp->coinaddrs[slot],addrtype,hexstr); } else hexstr[0] = 0; for (i=0; iN; i++) if ( GETBIT(&dp->readymask,i) == 0 ) break; if ( i == dp->N )//dp->readymask == ((1 << dp->N) - 1) ) { if ( hn->server->H.slot == pangea_slotA(sp) && senderind != 0 ) pangea_sendcmd(hex,hn,"ready",-1,sp->btcpub,sizeof(sp->btcpub),0,0); for (i=0; iN; i++) pubkeys[i] = sp->btcpubkeys[pangea_slot(sp,i)]; retval = create_MofN(p2shtype,sp->redeemScript,sp->scriptPubKey,sp->multisigaddr,pubkeys,dp->M,dp->N); PostMessage("retval.%d scriptPubKey.(%s) multisigaddr.(%s) redeemScript.(%s)\n",retval,sp->scriptPubKey,sp->multisigaddr,sp->redeemScript); } PostMessage("player.%d got ready from senderind.%d slot.%d readymask.%x btcpubkey.(%s) (%s) wip.(%s)\n",hn->client->H.slot,senderind,slot,dp->readymask,hexstr,sp->coinaddrs[slot],sp->wipstr); /*if ( 0 && hn->client->H.slot == pangea_slotA(dp->table) ) { if ( (dp->pmworks & (1 << senderind)) == 0 ) { PostMessage("send pmtest from %d to %d\n",hn->client->H.slot,senderind); pangea_sendcmd(hex,hn,"pmtest",-1,dp->hand.checkprod.bytes,sizeof(uint64_t),-1,-1); pangea_sendcmd(hex,hn,"pmtest",senderind,dp->hand.checkprod.bytes,sizeof(uint64_t),-1,senderind); } }*/ return(0); } void pangea_rwaudit(int32_t saveflag,bits256 *audit,bits256 *audits,int32_t cardi,int32_t destplayer,int32_t N) { int32_t i; audits = &audits[(cardi * N + destplayer) * N]; if ( saveflag != 0 ) { for (i=0; itable; if ( data == 0 || datalen != sizeof(bits256)*dp->N ) { PostMessage("pangea_card invalid datalen.%d vs %ld\n",datalen,(long)sizeof(bits256)*dp->N); return(-1); } //PostMessage("pangea_card priv.%llx\n",(long long)hn->client->H.privkey.txid); destplayer = juint(json,"dest"); pangea_rwaudit(1,(void *)data,priv->audits,cardi,destplayer,dp->N); pangea_rwaudit(0,audit,priv->audits,cardi,destplayer,dp->N); //PostMessage("card.%d destplayer.%d [%llx]\n",cardi,destplayer,(long long)audit[0].txid); if ( (card= cards777_checkcard(&cardpriv,cardi,pangea_ind(dp->table,hn->client->H.slot),destplayer,hn->client->H.privkey,dp->hand.cardpubs,dp->numcards,audit[0])) >= 0 ) { destplayer = pangea_ind(dp->table,hn->client->H.slot); if ( Debuglevel > 2 ) PostMessage("player.%d got card.[%d]\n",hn->client->H.slot,card); //memcpy(&priv->incards[cardi*dp->N + destplayer],cardpriv.bytes,sizeof(bits256)); selector = (cardi / dp->N); priv->holecards[selector] = cardpriv; priv->cardis[selector] = cardi; dp->hand.hands[destplayer][5 + selector] = priv->hole[selector] = cardpriv.bytes[1]; validcard = 1; cardAstr[0] = cardBstr[0] = 0; if ( priv->hole[0] != 0xff ) cardstr(cardAstr,priv->hole[0]); if ( priv->hole[1] != 0xff ) cardstr(cardBstr,priv->hole[1]); PostMessage(">>>>>>>>>> dest.%d priv.%p holecards[%02d] cardi.%d / dp->N %d (%02d %02d) -> (%s %s)\n",destplayer,priv,priv->hole[cardi / dp->N],cardi,dp->N,priv->hole[0],priv->hole[1],cardAstr,cardBstr); if ( cards777_validate(cardpriv,dp->hand.final[cardi*dp->N + destplayer],dp->hand.cardpubs,dp->numcards,audit,dp->N,sp->playerpubs[hn->client->H.slot]) < 0 ) PostMessage("player.%d decoded cardi.%d card.[%02d] but it doesnt validate\n",hn->client->H.slot,cardi,card); } else PostMessage("ERROR player.%d got no card %llx\n",hn->client->H.slot,*(long long *)data); if ( cardi < dp->N*2 ) pangea_sendcmd(hex,hn,"facedown",-1,(void *)&cardi,sizeof(cardi),cardi,validcard); else pangea_sendcmd(hex,hn,"faceup",-1,cardpriv.bytes,sizeof(cardpriv),cardi,0xff); return(0); } int32_t pangea_decoded(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { int32_t cardi,destplayer,card,turni; bits256 cardpriv,audit[CARDS777_MAXPLAYERS]; char hex[1024]; struct pangea_info *sp = dp->table; if ( data == 0 || datalen != sizeof(bits256)*dp->N ) { PostMessage("pangea_decoded invalid datalen.%d vs %ld\n",datalen,(long)sizeof(bits256)); return(-1); } cardi = juint(json,"cardi"); turni = juint(json,"turni"); if ( cardi < dp->N*2 || cardi >= dp->N*2 + 5 ) { PostMessage("pangea_decoded invalid cardi.%d\n",cardi); return(-1); } destplayer = pangea_ind(dp->table,0); pangea_rwaudit(1,(void *)data,priv->audits,cardi,destplayer,dp->N); pangea_rwaudit(0,audit,priv->audits,cardi,destplayer,dp->N); //memcpy(&priv->incards[cardi*dp->N + destplayer],data,sizeof(bits256)); if ( turni == pangea_ind(dp->table,hn->client->H.slot) ) { if ( hn->client->H.slot != pangea_slotA(dp->table) ) { audit[0] = cards777_decode(&audit[sp->myind],priv->xoverz,destplayer,audit[0],priv->outcards,dp->numcards,dp->N); pangea_rwaudit(1,audit,priv->audits,cardi,destplayer,dp->N); pangea_sendcmd(hex,hn,"decoded",-1,audit[0].bytes,sizeof(bits256)*dp->N,cardi,pangea_prevnode(dp->table)); //PostMessage("player.%d decoded cardi.%d %llx -> %llx\n",hn->client->H.slot,cardi,(long long)priv->incards[cardi*dp->N + destplayer].txid,(long long)decoded.txid); } else { if ( (card= cards777_checkcard(&cardpriv,cardi,pangea_ind(dp->table,hn->client->H.slot),pangea_ind(dp->table,hn->client->H.slot),hn->client->H.privkey,dp->hand.cardpubs,dp->numcards,audit[0])) >= 0 ) { if ( cards777_validate(cardpriv,dp->hand.final[cardi*dp->N + destplayer],dp->hand.cardpubs,dp->numcards,audit,dp->N,sp->playerpubs[hn->client->H.slot]) < 0 ) PostMessage("player.%d decoded cardi.%d card.[%d] but it doesnt validate\n",hn->client->H.slot,cardi,card); pangea_sendcmd(hex,hn,"faceup",-1,cardpriv.bytes,sizeof(cardpriv),cardi,cardpriv.txid!=0?0xff:-1); //PostMessage("-> FACEUP.(%s)\n",hex); } } } return(0); } int32_t pangea_zbuf(char *zbuf,uint8_t *data,int32_t datalen) { int i,j,n = 0; for (i=0; i>4) & 0xf); zbuf[n++] = hexbyte(data[i] & 0xf); } else { for (j=1; j<16; j++) if ( data[i+j] != 0 ) break; i += (j - 1); zbuf[n++] = 'Z'; zbuf[n++] = 'A'+j; } } zbuf[n] = 0; return(n); } int32_t pangea_unzbuf(uint8_t *buf,char *hexstr,int32_t len) { int32_t i,j,len2; for (len2=i=0; itable; if ( data == 0 || datalen != (2 * dp->N) * (dp->N * dp->N * sizeof(bits256)) || (hex= malloc(maxlen)) == 0 ) { PostMessage("pangea_preflop invalid datalen.%d vs %ld\n",datalen,(long)(2 * dp->N) * (dp->N * dp->N * sizeof(bits256))); return(-1); } //PostMessage("preflop player.%d\n",hn->client->H.slot); //memcpy(priv->incards,data,datalen); memcpy(priv->audits,data,datalen); if ( hn->client->H.slot != pangea_slotA(dp->table) && hn->client->H.slot != pangea_slotB(dp->table) ) { //for (i=0; inumcards*dp->N; i++) // PostMessage("%llx ",(long long)priv->outcards[i].txid); //PostMessage("player.%d outcards\n",hn->client->H.slot); for (cardi=0; cardiN*2; cardi++) for (destplayer=0; destplayerN; destplayer++) { pangea_rwaudit(0,audit,priv->audits,cardi,destplayer,dp->N); if ( 0 && (card= cards777_checkcard(&cardpriv,cardi,pangea_ind(dp->table,hn->client->H.slot),destplayer,hn->client->H.privkey,dp->hand.cardpubs,dp->numcards,audit[0])) >= 0 ) PostMessage("ERROR: unexpected decode player.%d got card.[%d]\n",hn->client->H.slot,card); audit[0] = cards777_decode(&audit[sp->myind],priv->xoverz,destplayer,audit[0],priv->outcards,dp->numcards,dp->N); pangea_rwaudit(1,audit,priv->audits,cardi,destplayer,dp->N); } //PostMessage("issue preflop\n"); if ( (zbuf= calloc(1,datalen*2+1)) != 0 ) { //init_hexbytes_noT(zbuf,priv->audits[0].bytes,datalen); //PostMessage("STARTZBUF.(%s)\n",zbuf); len = pangea_zbuf(zbuf,priv->audits[0].bytes,datalen); { int32_t len2; len2 = pangea_unzbuf((void *)hex,zbuf,len); if ( len2 != datalen || memcmp(hex,priv->audits[0].bytes,datalen) != 0 ) { if ( _crc32(0,(void *)hex,datalen) != _crc32(0,priv->audits[0].bytes,datalen) ) { PostMessage("zbuf error len2.%d vs datalen.%d crcs %u vs %u\n%s\n",len2,datalen,_crc32(0,(void *)hex,datalen),_crc32(0,priv->audits[0].bytes,datalen),hex); getchar(); } } } //PostMessage("datalen.%d -> len.%d zbuf %ld\n",datalen,len,(long)strlen(zbuf)); pangea_sendcmd(hex,hn,"preflop",pangea_prevnode(dp->table),(void *)zbuf,len,dp->N * 2 * dp->N,-1); free(zbuf); } } else { //PostMessage("sendout cards\n"); for (iter=cardi=0; iter<2; iter++) for (i=0; iN; i++,cardi++) { destplayer = (dp->button + i) % dp->N; pangea_rwaudit(0,audit,priv->audits,cardi,destplayer,dp->N); //PostMessage("audit[0] %llx -> ",(long long)audit[0].txid); audit[0] = cards777_decode(&audit[sp->myind],priv->xoverz,destplayer,audit[0],priv->outcards,dp->numcards,dp->N); pangea_rwaudit(1,audit,priv->audits,cardi,destplayer,dp->N); //PostMessage("[%llx + %llx] ",*(long long *)&audit[0],(long long)&audit[pangea_ind(dp->table,hn->client->H.slot)]); if ( destplayer == pangea_ind(dp->table,hn->client->H.slot) ) pangea_card(hn,json,dp,priv,audit[0].bytes,sizeof(bits256)*dp->N,cardi,destplayer); else pangea_sendcmd(hex,hn,"card",destplayer,audit[0].bytes,sizeof(bits256)*dp->N,cardi,-1); } } free(hex); return(0); } int32_t pangea_encoded(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { char *hex; bits256 audit[CARDS777_MAXPLAYERS]; int32_t i,iter,cardi,destplayer; struct pangea_info *sp = dp->table; if ( data == 0 || datalen != (dp->numcards * dp->N) * sizeof(bits256) ) { PostMessage("pangea_encode invalid datalen.%d vs %ld\n",datalen,(long)((dp->numcards * dp->N) * sizeof(bits256))); return(-1); } cards777_encode(priv->outcards,priv->xoverz,priv->allshares,priv->myshares,dp->hand.sharenrs[pangea_ind(dp->table,hn->client->H.slot)],dp->M,(void *)data,dp->numcards,dp->N); //int32_t i; for (i=0; inumcards*dp->N; i++) // PostMessage("%llx ",(long long)priv->outcards[i].txid); PostMessage("player.%d ind.%d encodes into %p %llx -> %llx next.%d dp->N %d\n",hn->client->H.slot,pangea_ind(sp,hn->client->H.slot),priv->outcards,(long long)*(uint64_t *)data,(long long)priv->outcards[0].txid,pangea_nextnode(sp),dp->N); if ( pangea_ind(sp,hn->client->H.slot) > 0 && (hex= malloc(65536)) != 0 ) { if ( pangea_ind(sp,hn->client->H.slot) < sp->numactive-1 ) { //PostMessage("send encoded\n"); pangea_sendcmd(hex,hn,"encoded",pangea_nextnode(sp),priv->outcards[0].bytes,datalen,dp->N*dp->numcards,-1); } else { memcpy(dp->hand.final,priv->outcards,sizeof(bits256)*dp->N*dp->numcards); pangea_sendcmd(hex,hn,"final",-1,priv->outcards[0].bytes,datalen,dp->N*dp->numcards,-1); for (iter=cardi=0; iter<2; iter++) for (i=0; iN; i++,cardi++) for (destplayer=0; destplayerN; destplayer++) { pangea_rwaudit(0,audit,priv->audits,cardi,destplayer,dp->N); audit[0] = dp->hand.final[cardi*dp->N + destplayer]; pangea_rwaudit(1,audit,priv->audits,cardi,destplayer,dp->N); } PostMessage("call preflop %ld\n",(long)((2 * dp->N) * (dp->N * dp->N * sizeof(bits256)))); pangea_preflop(hn,json,dp,priv,priv->audits[0].bytes,(2 * dp->N) * (dp->N * dp->N * sizeof(bits256)),pangea_ind(sp,hn->client->H.slot)); } free(hex); } return(0); } int32_t pangea_final(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { if ( data == 0 || datalen != (dp->numcards * dp->N) * sizeof(bits256) ) { PostMessage("pangea_final invalid datalen.%d vs %ld\n",datalen,(long)((dp->numcards * dp->N) * sizeof(bits256))); return(-1); } if ( Debuglevel > 2 ) PostMessage("player.%d final into %p\n",hn->client->H.slot,priv->outcards); memcpy(dp->hand.final,data,sizeof(bits256) * dp->N * dp->numcards); return(0); } int32_t pangea_facedown(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t cardi,int32_t senderind) { int32_t i,validcard,n = 0; if ( data == 0 || datalen != sizeof(int32_t) ) { PostMessage("pangea_facedown invalid datalen.%d vs %ld\n",datalen,(long)sizeof(bits256)); return(-1); } validcard = juint(json,"turni"); if ( validcard > 0 ) dp->hand.havemasks[senderind] |= (1LL << cardi); for (i=0; iN; i++) { if ( Debuglevel > 2 ) PostMessage("%llx ",(long long)dp->hand.havemasks[i]); if ( bitweight(dp->hand.havemasks[i]) == 2 ) n++; } if ( Debuglevel > 2 ) PostMessage(" | player.%d sees that destplayer.%d got cardi.%d valid.%d | %llx | n.%d\n",hn->client->H.slot,senderind,cardi,validcard,(long long)dp->hand.havemasks[senderind],n); if ( hn->client->H.slot == pangea_slotA(dp->table) && n == dp->N ) pangea_startbets(hn,dp,dp->N*2); return(0); } uint32_t pangea_rank(struct cards777_pubdata *dp,int32_t senderind) { int32_t i; char handstr[128]; if ( dp->hand.handranks[senderind] != 0 ) return(dp->hand.handranks[senderind]); for (i=0; i<7; i++) { if ( i < 5 ) dp->hand.hands[senderind][i] = dp->hand.community[i]; if ( dp->hand.hands[senderind][i] == 0xff ) break; } if ( i == 7 ) { dp->hand.handranks[senderind] = set_handstr(handstr,dp->hand.hands[senderind],0); dp->hand.handmask |= (1 << senderind); PostMessage("sender.%d (%s) rank.%x handmask.%x\n",senderind,handstr,dp->hand.handranks[senderind],dp->hand.handmask); } return(dp->hand.handranks[senderind]); } int32_t pangea_faceup(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { int32_t cardi,validcard,i; char hexstr[65]; uint16_t tmp; if ( data == 0 || datalen != sizeof(bits256) ) { PostMessage("pangea_faceup invalid datalen.%d vs %ld\n",datalen,(long)((dp->numcards + 1) * sizeof(bits256))); return(-1); } init_hexbytes_noT(hexstr,data,sizeof(bits256)); cardi = juint(json,"cardi"); validcard = ((int32_t)juint(json,"turni")) >= 0; if ( Debuglevel > 2 || hn->client->H.slot == pangea_slotA(dp->table) ) { char *str = jprint(json,0); PostMessage("from.%d -> player.%d COMMUNITY.[%d] (%s) cardi.%d valid.%d (%s)\n",senderind,hn->client->H.slot,data[1],hexstr,cardi,validcard,str); free(str); } //PostMessage("got FACEUP.(%s)\n",jprint(json,0)); if ( validcard > 0 ) { tmp = (cardi << 8); tmp |= (juint(json,"turni") & 0xff); pangea_summary(hn,dp,CARDS777_FACEUP,&tmp,sizeof(tmp),data,sizeof(bits256)); if ( cardi >= dp->N*2 && cardi < dp->N*2+5 ) { dp->hand.community[cardi - dp->N*2] = data[1]; for (i=0; iN; i++) dp->hand.hands[i][cardi - dp->N*2] = data[1]; memcpy(dp->hand.community256[cardi - dp->N*2].bytes,data,sizeof(bits256)); //PostMessage("set community[%d] <- %d\n",cardi - dp->N*2,data[1]); if ( senderind == pangea_ind(dp->table,hn->client->H.slot) ) pangea_rank(dp,senderind); //PostMessage("calc rank\n"); if ( hn->client->H.slot == pangea_slotA(dp->table) && cardi >= dp->N*2+2 && cardi < dp->N*2+5 ) pangea_startbets(hn,dp,cardi+1); //else PostMessage("dont start bets %d\n",cardi+1); } else { //PostMessage("valid.%d cardi.%d vs N.%d\n",validcard,cardi,dp->N); if ( cardi < dp->N*2 ) { memcpy(dp->hand.cards[senderind][cardi/dp->N].bytes,data,sizeof(bits256)); dp->hand.hands[senderind][5 + cardi/dp->N] = data[1]; pangea_rank(dp,senderind); } } } return(0); } void pangea_serverstate(union hostnet777 *hn,struct cards777_pubdata *dp,struct cards777_privdata *priv) { int32_t i,j,n; struct pangea_info *sp = dp->table; if ( dp->hand.finished != 0 && time(NULL) > dp->hand.finished+PANGEA_HANDGAP ) { PostMessage("HANDGAP\n"); pangea_anotherhand(hn,dp,3); } if ( dp->hand.betstarted == 0 && dp->newhand[0] == 0 ) { static uint32_t disptime; for (i=n=0; iN; i++) { if ( Debuglevel > 2 ) PostMessage("%llx ",(long long)dp->hand.havemasks[i]); if ( bitweight(dp->hand.havemasks[i]) == 2 ) n++; } if ( n < dp->N ) { for (i=0; iN; i++) { if ( sp->balances[pangea_slot(sp,i)] < dp->minbuyin*dp->bigblind || sp->balances[pangea_slot(sp,i)] > dp->maxbuyin*dp->bigblind ) break; } if ( i == dp->N && dp->numhands < 2 ) { if ( time(NULL) > dp->hand.startdecktime+60 ) { PostMessage("send newdeck len.%ld\n",(long)strlen(dp->newhand)); pangea_newdeck(hn); PostMessage("sent newdeck %ld\n",(long)strlen(dp->newhand)); } } else if ( disptime != time(NULL) && (time(NULL) % 60) == 0 ) { disptime = (uint32_t)time(NULL); for (j=0; jN; j++) PostMessage("%.8f ",dstr(sp->balances[pangea_slot(sp,i)])); PostMessage("no buyin for %d (%.8f %.8f)\n",i,dstr(dp->minbuyin*dp->bigblind),dstr(dp->maxbuyin*dp->bigblind)); } } } else pangea_checkstart(hn,dp,priv); } /*int32_t pangea_pmtest(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { int32_t turni,cardi; char hex[2048]; cardi = juint(json,"cardi"); turni = juint(json,"turni"); if ( senderind >= 0 && senderind < dp->N ) { if ( cardi < 0 ) { if ( turni >= 0 ) dp->pmviaworks |= (1 << senderind); else dp->broadcastworks |= (1 << senderind); } else { if ( turni >= 0 ) dp->pmworks |= (1 << senderind); else dp->pmviaworks |= (1 << senderind); } if ( dp->pmworks != ((1 << dp->N) - 1) ) { //PostMessage("PMworks: %x %x %x\n",dp->pmworks,dp->pmviaworks,dp->broadcastworks); } } //PostMessage("got pmtest.%d from %d cardi.%d\n",turni,senderind,cardi); if ( hn->client->H.slot == 0 ) { if ( dp->pmworks == ((1 << dp->N) - 1) ) { //PostMessage("all pms work\n"); } } else { if ( dp->pmworks != ((1 << dp->N) - 1) ) { pangea_sendcmd(hex,hn,"pmtest",senderind,dp->hand.checkprod.bytes,sizeof(uint64_t),senderind,turni); pangea_sendcmd(hex,hn,"pmtest",-1,dp->hand.checkprod.bytes,sizeof(uint64_t),-1,turni); } } return(0); }*/ int32_t pangea_ping(union hostnet777 *hn,cJSON *json,struct cards777_pubdata *dp,struct cards777_privdata *priv,uint8_t *data,int32_t datalen,int32_t senderind) { dp->hand.othercardpubs[senderind] = *(uint64_t *)data; if ( senderind == 0 ) { /*dp->hand.undergun = juint(json,"turni"); dp->hand.cardi = juint(json,"cardi"); if ( (array= jarray(&n,json,"community")) != 0 ) { for (i=0; ihand.community[i] = juint(jitem(array,i),0); }*/ } //PostMessage("player.%d GOTPING.(%s) %llx\n",hn->client->H.slot,jprint(json,0),(long long)dp->othercardpubs[senderind]); return(0); } void pangea_chat(uint64_t senderbits,void *buf,int32_t len,int32_t senderind) { PostMessage(">>>>>>>>>>> CHAT FROM.%d %llu: (%s)\n",senderind,(long long)senderbits,(char *)buf); } int32_t pangea_poll(uint64_t *senderbitsp,uint32_t *timestampp,union hostnet777 *hn) { char *jsonstr,*hexstr,*cmdstr; cJSON *json; struct cards777_privdata *priv; struct cards777_pubdata *dp; struct pangea_info *sp; int32_t len,senderind,maxlen; uint8_t *buf; *senderbitsp = 0; dp = hn->client->H.pubdata, sp = dp->table; priv = hn->client->H.privdata; if ( hn == 0 || hn->client == 0 || dp == 0 || priv == 0 ) { if ( Debuglevel > 2 ) PostMessage("pangea_poll: null hn.%p %p dp.%p priv.%p\n",hn,hn!=0?hn->client:0,dp,priv); return(-1); } maxlen = (int32_t)(sizeof(bits256) * dp->N*dp->N*dp->numcards); if ( (buf= malloc(maxlen)) == 0 ) { PostMessage("pangea_poll: null buf\n"); return(-1); } if ( dp != 0 && priv != 0 && (jsonstr= queue_dequeue(&hn->client->H.Q,1)) != 0 ) { //pangea_neworder(dp,dp->table,0,0); //PostMessage("player.%d GOT.(%s)\n",hn->client->H.slot,jsonstr); if ( (json= cJSON_Parse(jsonstr)) != 0 ) { *senderbitsp = j64bits(json,"sender"); if ( (senderind= juint(json,"myind")) < 0 || senderind >= dp->N ) { PostMessage("pangea_poll: illegal senderind.%d cardi.%d turni.%d (%s)\n",senderind,juint(json,"cardi"),juint(json,"turni"),jsonstr); goto cleanup; } *timestampp = juint(json,"timestamp"); hn->client->H.state = juint(json,"state"); len = juint(json,"n"); cmdstr = jstr(json,"cmd"); if ( sp->myind < 0 ) { // check for reactivation command goto cleanup; } if ( cmdstr != 0 && strcmp(cmdstr,"preflop") == 0 ) { if ( (hexstr= jstr(json,"data")) != 0 ) len = pangea_unzbuf(buf,hexstr,len); } else if ( (hexstr= jstr(json,"data")) != 0 && strlen(hexstr) == (len<<1) ) { if ( len > maxlen ) { PostMessage("len too big for pangea_poll\n"); goto cleanup; } decode_hex(buf,len,hexstr); } else if ( hexstr != 0 ) PostMessage("len.%d vs hexlen.%ld (%s)\n",len,(long)(strlen(hexstr)>>1),hexstr); if ( cmdstr != 0 ) { if ( strcmp(cmdstr,"newhand") == 0 ) pangea_newhand(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"ping") == 0 ) pangea_ping(hn,json,dp,priv,buf,len,senderind); //else if ( strcmp(cmdstr,"pmtest") == 0 ) // pangea_pmtest(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"gotdeck") == 0 ) pangea_gotdeck(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"ready") == 0 ) pangea_ready(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"encoded") == 0 ) pangea_encoded(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"final") == 0 ) pangea_final(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"addfunds") == 0 ) pangea_addfunds(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"preflop") == 0 ) pangea_preflop(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"decoded") == 0 ) pangea_decoded(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"card") == 0 ) pangea_card(hn,json,dp,priv,buf,len,juint(json,"cardi"),senderind); else if ( strcmp(cmdstr,"facedown") == 0 ) pangea_facedown(hn,json,dp,priv,buf,len,juint(json,"cardi"),senderind); else if ( strcmp(cmdstr,"faceup") == 0 ) pangea_faceup(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"turn") == 0 ) pangea_turn(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"confirmturn") == 0 ) pangea_confirmturn(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"chat") == 0 ) pangea_chat(*senderbitsp,buf,len,senderind); else if ( strcmp(cmdstr,"action") == 0 ) pangea_action(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"showdown") == 0 ) pangea_showdown(hn,json,dp,priv,buf,len,senderind); else if ( strcmp(cmdstr,"summary") == 0 ) pangea_gotsummary(hn,json,dp,priv,buf,len,senderind); } cleanup: free_json(json); } free_queueitem(jsonstr); } free(buf); return(hn->client->H.state); } char *pangea_status(uint64_t my64bits,uint64_t tableid,cJSON *json) { int32_t i,j,threadid = juint(json,"threadid"); struct pangea_info *sp; cJSON *item,*array=0,*retjson = 0; if ( tableid != 0 ) { if ( (sp= pangea_find(tableid,threadid)) != 0 ) { if ( (item= pangea_tablestatus(sp)) != 0 ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jadd(retjson,"table",item); return(jprint(retjson,1)); } } } else { for (i=0; inumaddrs; j++) if ( sp->addrs[j] == my64bits ) { if ( (item= pangea_tablestatus(sp)) != 0 ) { if ( array == 0 ) array = cJSON_CreateArray(); jaddi(array,item); } break; } } } } retjson = cJSON_CreateObject(); if ( array == 0 ) jaddstr(retjson,"error","no table status"); else { jaddstr(retjson,"result","success"); jadd(retjson,"tables",array); } jadd64bits(retjson,"nxtaddr",my64bits); return(jprint(retjson,1)); } int32_t pangea_idle(struct plugin_info *plugin) { int32_t i,n,m,pinggap = 1; uint64_t senderbits; uint32_t timestamp; struct pangea_thread *tp; union hostnet777 *hn; struct cards777_pubdata *dp; char hex[1024]; while ( 1 ) { for (i=n=m=0; i<_PANGEA_MAXTHREADS; i++) { if ( (tp= THREADS[i]) != 0 ) { hn = &tp->hn; //PostMessage("pangea idle player.%d\n",hn->client->H.slot); if ( hn->client->H.done == 0 ) { n++; if ( hostnet777_idle(hn) != 0 ) m++; pangea_poll(&senderbits,×tamp,hn); dp = hn->client->H.pubdata; if ( dp != 0 && hn->client->H.slot == pangea_slotA(dp->table) ) pinggap = 1; if ( hn->client != 0 && dp != 0 ) { if ( time(NULL) > hn->client->H.lastping + pinggap ) { if ( 0 && (dp= hn->client->H.pubdata) != 0 ) { pangea_sendcmd(hex,hn,"ping",-1,dp->hand.checkprod.bytes,sizeof(uint64_t),dp->hand.cardi,dp->hand.undergun); hn->client->H.lastping = (uint32_t)time(NULL); } } if ( dp->hand.handmask == ((1 << dp->N) - 1) && dp->hand.finished == 0 )//&& dp->hand.pangearake == 0 ) { PostMessage("P%d: all players folded or showed cards at %ld | rakemillis %d\n",hn->client->H.slot,(long)time(NULL),dp->rakemillis); pangea_finish(hn,dp); } if ( hn->client->H.slot == pangea_slotA(dp->table) ) pangea_serverstate(hn,dp,hn->server->H.privdata); } } } } if ( n == 0 ) break; if ( m == 0 ) msleep(3); } //for (i=0; i<_PANGEA_MAXTHREADS; i++) // if ( THREADS[i] != 0 && Pangea_waiting != 0 ) // pangea_userpoll(&THREADS[i]->hn); return(0); } void pangea_buyins(uint32_t *minbuyinp,uint32_t *maxbuyinp) { if ( *minbuyinp == 0 && *maxbuyinp == 0 ) { *minbuyinp = 100; *maxbuyinp = 1000; } else { PostMessage("minbuyin.%d maxbuyin.%d -> ",*minbuyinp,*maxbuyinp); if ( *minbuyinp < 20 ) *minbuyinp = 20; if ( *maxbuyinp < *minbuyinp ) *maxbuyinp = (*minbuyinp * 4); if ( *maxbuyinp > 1000 ) *maxbuyinp = 1000; if ( *minbuyinp > *maxbuyinp ) *minbuyinp = *maxbuyinp; PostMessage("(%d %d)\n",*minbuyinp,*maxbuyinp); } } struct pangea_info *pangea_create(struct pangea_thread *tp,int32_t *createdflagp,char *base,uint32_t timestamp,uint64_t *addrs,int32_t numaddrs,uint64_t bigblind,uint64_t ante,uint64_t *isbot,uint32_t minbuyin,uint32_t maxbuyin,int32_t hostrake) { struct pangea_info *sp = 0; bits256 hash; int32_t i,j,numcards,firstslot = -1; struct cards777_privdata *priv; struct cards777_pubdata *dp; if ( createdflagp != 0 ) *createdflagp = 0; for (i=0; inxt64bits ) break; } if ( i == numaddrs ) { PostMessage("this node not in addrs\n"); return(0); } if ( numaddrs > 0 && (sp= calloc(1,sizeof(*sp))) != 0 ) { sp->tp = tp; numcards = CARDS777_MAXCARDS; pangea_buyins(&minbuyin,&maxbuyin); tp->numcards = numcards, tp->N = numaddrs; sp->numactive = numaddrs; sp->dp = dp = cards777_allocpub((numaddrs >> 1) + 1,numcards,numaddrs); dp->minbuyin = minbuyin, dp->maxbuyin = maxbuyin; sp->minbuyin = minbuyin, sp->maxbuyin = maxbuyin; dp->rakemillis = hostrake; if ( dp->rakemillis > PANGEA_MAX_HOSTRAKE ) dp->rakemillis = PANGEA_MAX_HOSTRAKE; dp->rakemillis += PANGEA_MINRAKE_MILLIS; if ( dp == 0 ) { PostMessage("pangea_create: unexpected out of memory pub\n"); return(0); } for (j=0; j<5; j++) dp->hand.community[j] = 0xff; memcpy(sp->addrs,addrs,numaddrs * sizeof(sp->addrs[0])); for (j=0; jbalances[j] = balances[j]; //else dp->balances[j] = 100; if ( isbot != 0 ) sp->isbot[j] = isbot[j]; sp->active[j] = addrs[j]; } sp->priv = priv = cards777_allocpriv(numcards,numaddrs); priv->hole[0] = priv->hole[1] = 0xff; if ( priv == 0 ) { PostMessage("pangea_create: unexpected out of memory priv\n"); return(0); } priv->automuck = Showmode; priv->autofold = Autofold; btc_priv2pub(sp->btcpub,tp->hn.client->H.privkey.bytes); init_hexbytes_noT(sp->btcpubkeystr,sp->btcpub,33); strcpy(sp->coinstr,base); strcpy(dp->coinstr,base); sp->addrtype = coin777_addrtype(&sp->p2shtype,base); sp->wiftype = coin777_wiftype(base); btc_priv2wip(sp->wipstr,tp->hn.client->H.privkey.bytes,sp->wiftype); strcpy(sp->btcpubkeys[sp->myslot],sp->btcpubkeystr); PostMessage("T%d: Automuck.%d Autofold.%d rakemillis.%d btcpubkey.(%s) (%s) addrtype.%02x p2sh.%02x wif.%02x\n",tp->hn.client->H.slot,priv->automuck,priv->autofold,dp->rakemillis,sp->btcpubkeystr,dp->coinstr,sp->addrtype,sp->p2shtype,sp->wiftype); if ( (sp->timestamp= timestamp) == 0 ) sp->timestamp = (uint32_t)time(NULL); sp->numaddrs = sp->numactive = numaddrs; sp->basebits = stringbits(base); sp->bigblind = dp->bigblind = bigblind, sp->ante = dp->ante = ante; vcalc_sha256(0,hash.bytes,(uint8_t *)sp,numaddrs * sizeof(sp->addrs[0]) + 4*sizeof(uint32_t) + 3*sizeof(uint64_t)); sp->tableid = hash.txid; for (i=0; itableid == TABLES[i]->tableid && tp->threadid == TABLES[i]->tp->threadid ) { PostMessage("tableid %llu already exists!\n",(long long)sp->tableid); free(sp); return(TABLES[i]); } } else if ( firstslot < 0 ) firstslot = i; } TABLES[firstslot] = sp; if ( createdflagp != 0 ) *createdflagp = 1; } return(sp); } cJSON *pangea_ciphersjson(struct cards777_pubdata *dp,struct cards777_privdata *priv) { int32_t i,j,nonz = 0; char hexstr[65]; cJSON *array = cJSON_CreateArray(); for (i=0; inumcards; i++) for (j=0; jN; j++,nonz++) { init_hexbytes_noT(hexstr,priv->outcards[nonz].bytes,sizeof(bits256)); jaddistr(array,hexstr); } return(array); } cJSON *pangea_playerpubs(bits256 *playerpubs,int32_t num) { int32_t i; char hexstr[65]; cJSON *array = cJSON_CreateArray(); for (i=0; i %s) ",(long long)playerpubs[i].txid,hexstr); jaddistr(array,hexstr); } //PostMessage("playerpubs\n"); return(array); } cJSON *pangea_cardpubs(struct cards777_pubdata *dp) { int32_t i; char hexstr[65]; cJSON *array = cJSON_CreateArray(); for (i=0; inumcards; i++) { init_hexbytes_noT(hexstr,dp->hand.cardpubs[i].bytes,sizeof(bits256)); jaddistr(array,hexstr); } init_hexbytes_noT(hexstr,dp->hand.checkprod.bytes,sizeof(bits256)); jaddistr(array,hexstr); return(array); } cJSON *pangea_sharenrs(uint8_t *sharenrs,int32_t n) { int32_t i; cJSON *array = cJSON_CreateArray(); for (i=0; i CARDS777_MAXPLAYERS ) { PostMessage("no address or illegal num.%d\n",num); return(clonestr("{\"error\":\"no addrs or illegal numplayers\"}")); } for (i=0; ihn.server = srv; memcpy(srv->H.privkey.bytes,privkey.bytes,sizeof(bits256)); memcpy(srv->H.pubkey.bytes,pubkey.bytes,sizeof(bits256)); } } else { PANGEA_MAXTHREADS = 1; if ( (endpoint= jstr(json,"pangea_endpoint")) != 0 ) { if ( strncmp(endpoint,"tcp://127.0.0.1",strlen("tcp://127.0.0.1")) == 0 || strncmp(endpoint,"ws://127.0.0.1",strlen("ws://127.0.0.1")) == 0 ) { PostMessage("ILLEGAL pangea_endpoint.(%s)\n",endpoint); return(clonestr("{\"error\":\"contact pangea host and tell them to add myipaddr to their SuperNET.conf\"}")); } if ( (tp->hn.client= hostnet777_client(privkey,pubkey,endpoint,i)) == 0 ) { memcpy(tp->hn.client->H.privkey.bytes,privkey.bytes,sizeof(bits256)); memcpy(tp->hn.client->H.pubkey.bytes,pubkey.bytes,sizeof(bits256)); } } } tp->nxt64bits = my64bits; } } } if ( myind < 0 ) return(clonestr("{\"error\":\"this table is not for me\"}")); /*if ( (array= jarray(&num,json,"balances")) == 0 ) { PostMessage("no balances or illegal num.%d\n",num); return(clonestr("{\"error\":\"no balances or illegal numplayers\"}")); } for (i=0; idp; sp->myslot = sp->myind = myind; dp->table = sp; tp->numcards = dp->numcards, tp->N = dp->N, tp->M = dp->M; if ( threadid == 0 ) { tp->hn.server->clients[0].pubdata = dp; tp->hn.server->clients[0].privdata = sp->priv; tp->hn.server->H.pubdata = dp; tp->hn.server->H.privdata = sp->priv; } else { tp->hn.client->my.pubdata = dp; tp->hn.client->my.privdata = sp->priv; tp->hn.client->H.pubdata = dp; tp->hn.client->H.privdata = sp->priv; if ( THREADS[0] != 0 ) { THREADS[0]->hn.server->clients[threadid].pubdata = dp; THREADS[0]->hn.server->clients[threadid].privdata = sp->priv; } } if ( (array= jarray(&num,json,"playerpubs")) == 0 || num < 2 || num > CARDS777_MAXPLAYERS ) { PostMessage("no address or illegal num.%d\n",num); return(clonestr("{\"error\":\"no addrs or illegal numplayers\"}")); } for (i=0; iplayerpubs[i].bytes,sizeof(bits256),hexstr); PostMessage("set playerpubs.(%s) %llx\n",hexstr,(long long)sp->playerpubs[i].txid); if ( sp->playerpubs[i].txid == 0 ) { PostMessage("player.%d has no NXT pubkey\n",i); return(clonestr("{\"error\":\"not all players have published NXT pubkeys\"}")); } } if ( myind >= 0 && createdflag != 0 && addrs[myind] == tp->nxt64bits ) { memcpy(sp->addrs,addrs,sizeof(*addrs) * dp->N); dp->readymask |= (1 << sp->myslot); pangea_sendcmd(hex,&tp->hn,"ready",-1,sp->btcpub,sizeof(sp->btcpub),0,0); return(clonestr("{\"result\":\"newtable created\"}")); } else if ( createdflag == 0 ) { if ( sp->addrs[0] == tp->nxt64bits ) return(clonestr("{\"result\":\"this is my table\"}")); else return(clonestr("{\"result\":\"table already exists\"}")); } } return(clonestr("{\"error\":\"no tableid\"}")); } struct pangea_thread *pangea_threadinit(struct plugin_info *plugin,int32_t maxplayers) { struct pangea_thread *tp; struct hostnet777_server *srv; PANGEA_MAXTHREADS = 1; THREADS[0] = tp = calloc(1,sizeof(*THREADS[0])); if ( tp == 0 ) { PostMessage("pangea_threadinit: unexpected out of memory\n"); return(0); } tp->nxt64bits = plugin->nxt64bits; if ( (srv= hostnet777_server(*(bits256 *)plugin->mypriv,*(bits256 *)plugin->mypub,plugin->transport,plugin->ipaddr,plugin->pangeaport,9)) == 0 ) PostMessage("cant create hostnet777 server\n"); else { tp->hn.server = srv; memcpy(srv->H.privkey.bytes,plugin->mypriv,sizeof(bits256)); memcpy(srv->H.pubkey.bytes,plugin->mypub,sizeof(bits256)); } return(tp); } void pangea_create_newtable(char *retbuf,struct pangea_info *sp,struct cards777_pubdata *dp,uint64_t *isbot) { char *addrstr,*ciphers,*playerpubs,*isbotstr; isbotstr = jprint(addrs_jsonarray(isbot,dp->N),1); //balancestr = jprint(addrs_jsonarray(balances,num),1); addrstr = jprint(addrs_jsonarray(sp->addrs,dp->N),1); ciphers = jprint(pangea_ciphersjson(dp,sp->priv),1); playerpubs = jprint(pangea_playerpubs(sp->playerpubs,dp->N),1); dp->readymask |= (1 << sp->myslot); sprintf(retbuf,"{\"cmd\":\"newtable\",\"broadcast\":\"allnodes\",\"myind\":%d,\"pangea_endpoint\":\"%s\",\"plugin\":\"relay\",\"destplugin\":\"pangea\",\"method\":\"busdata\",\"submethod\":\"newtable\",\"my64bits\":\"%llu\",\"tableid\":\"%llu\",\"timestamp\":%u,\"M\":%d,\"N\":%d,\"base\":\"%s\",\"bigblind\":\"%llu\",\"minbuyin\":\"%d\",\"maxbuyin\":\"%u\",\"rakemillis\":\"%u\",\"ante\":\"%llu\",\"playerpubs\":%s,\"addrs\":%s,\"isbot\":%s,\"millitime\":\"%lld\"}",sp->myslot,sp->tp->hn.server->ep.endpoint,(long long)sp->tp->nxt64bits,(long long)sp->tableid,sp->timestamp,dp->M,dp->N,sp->coinstr,(long long)sp->bigblind,dp->minbuyin,dp->maxbuyin,dp->rakemillis,(long long)sp->ante,playerpubs,addrstr,isbotstr,(long long)hostnet777_convmT(&sp->tp->hn.server->H.mT,0)); //\"pluginrequest\":\"SuperNET\", PostMessage("START.(%s)\n",retbuf); //dp->pmworks |= (1 << sp->myind); free(addrstr), free(ciphers), free(playerpubs), free(isbotstr);// free(balancestr); } int32_t pangea_start(struct plugin_info *plugin,char *retbuf,char *base,uint32_t timestamp,uint64_t bigblind,uint64_t ante,int32_t hostrake,int32_t maxplayers,uint32_t minbuyin,uint32_t maxbuyin,cJSON *json) { char destNXT[64]; struct pangea_thread *tp; struct cards777_pubdata *dp; int32_t createdflag,addrtype,haspubkey,i,j,slot,n,myind=-1,r,num=0,threadid=0; uint64_t addrs[512],isbot[512],tmp; uint8_t p2shtype; struct pangea_info *sp; cJSON *bids,*walletitem,*item; memset(addrs,0,sizeof(addrs)); PostMessage("pangea_start rakemillis.%d\n",hostrake); //memset(balances,0,sizeof(balances)); pangea_buyins(&minbuyin,&maxbuyin); if ( hostrake < 0 || hostrake > PANGEA_MAX_HOSTRAKE ) { PostMessage("illegal hostrake.%d\n",hostrake); strcpy(retbuf,"{\"error\":\"illegal hostrake\"}"); return(-1); } if ( bigblind == 0 ) bigblind = SATOSHIDEN; if ( (tp= THREADS[threadid]) == 0 ) { pangea_threadinit(plugin,maxplayers); if ( (tp=THREADS[0]) == 0 ) { strcpy(retbuf,"{\"error\":\"uinitialized threadid\"}"); PostMessage("%s\n",retbuf); return(-1); } } PostMessage("mynxt64bits.%llu base.(%s) maxplayers.%d minbuyin.%u maxbuyin.%u\n",(long long)tp->nxt64bits,base,maxplayers,minbuyin,maxbuyin); if ( base == 0 || base[0] == 0 || maxplayers < 2 || maxplayers > CARDS777_MAXPLAYERS ) { sprintf(retbuf,"{\"error\":\"bad params\"}"); PostMessage("%s\n",retbuf); return(-1); } addrtype = coin777_addrtype(&p2shtype,base); if ( (bids= jarray(&n,json,"bids")) != 0 ) { PostMessage("numbids.%d\n",n); for (i=num=0; inxt64bits ) myind = num; PostMessage("%llu ",(long long)addrs[num]); num++; } } else PostMessage("%d: %llu mismatched walletitem bigblind %.8f ante %.8f rake %.1f%%\n",i,(long long)addrs[num],dstr(j64bits(walletitem,"bigblind")),dstr(j64bits(walletitem,"ante")),(double)juint(walletitem,"rakemillis")/10.); } } } PostMessage("(%llu) pangea_start(%s) threadid.%d myind.%d num.%d maxplayers.%d\n",(long long)tp->nxt64bits,base,tp->threadid,myind,num,maxplayers); if ( (i= myind) > 0 ) { addrs[i] = addrs[0]; addrs[0] = tp->nxt64bits; //tmp = balances[i]; //balances[i] = balances[0]; //balances[0] = tmp; tmp = isbot[i]; isbot[i] = isbot[0]; isbot[0] = tmp; i = 0; strcpy(retbuf,"{\"error\":\"host needs to be locally started and the first entry in addrs\"}"); return(-1); } while ( num > maxplayers ) { r = (rand() % (num-1)); PostMessage("swap out %d of %d\n",r+1,num); num--; isbot[r + 1] = isbot[num]; //balances[r + 1] = balances[num]; addrs[r + 1] = addrs[num]; } PostMessage("pangea numplayers.%d\n",num); if ( (sp= pangea_create(tp,&createdflag,base,timestamp,addrs,num,bigblind,ante,isbot,minbuyin,maxbuyin,hostrake)) == 0 ) { PostMessage("cant create table.(%s) numaddrs.%d\n",base,num); strcpy(retbuf,"{\"error\":\"cant create table, make sure all players have published NXT pubkeys\"}"); return(-1); } PostMessage("back from pangea_create\n"); dp = sp->dp, dp->table = sp; sp->myslot = sp->myind = myind; if ( createdflag != 0 && myind == 0 && addrs[myind] == tp->nxt64bits ) { tp->numcards = dp->numcards, tp->N = dp->N, tp->M = dp->M; PostMessage("myind.%d: hostrake.%d\n",myind,dp->rakemillis); dp->minbuyin = minbuyin, dp->maxbuyin = maxbuyin; tp->hn.server->clients[myind].pubdata = dp; tp->hn.server->clients[myind].privdata = sp->priv; tp->hn.server->H.pubdata = dp; tp->hn.server->H.privdata = sp->priv; for (j=0; jN; j++) { if ( THREADS[j] != 0 ) sp->playerpubs[j] = THREADS[j]->hn.client->H.pubkey; else { expand_nxt64bits(destNXT,addrs[j]); sp->playerpubs[j] = issue_getpubkey(&haspubkey,destNXT); if ( (slot= hostnet777_register(THREADS[0]->hn.server,sp->playerpubs[j],-1)) != j ) PostMessage("unexpected register slot.%d for j.%d\n",slot,j); } //PostMessage("thread[%d] pub.%llx priv.%llx\n",j,(long long)dp->playerpubs[j].txid,(long long)THREADS[j]->hn.client->H.privkey.txid); } pangea_create_newtable(retbuf,sp,dp,isbot); #ifdef BUNDLED if ( 1 ) { char *busdata_sync(uint32_t *noncep,char *jsonstr,char *broadcastmode,char *destNXTaddr); char *str; uint32_t nonce; if ( (str= busdata_sync(&nonce,retbuf,"allnodes",0)) != 0 ) free(str); } #endif } return(0); } char *pangea_history(uint64_t my64bits,uint64_t tableid,cJSON *json) { struct pangea_info *sp; if ( (sp= pangea_find64(tableid,my64bits)) != 0 && sp->dp != 0 ) { if ( jobj(json,"handid") == 0 ) return(pangea_dispsummary(sp,juint(json,"verbose"),sp->dp->summary,sp->dp->summarysize,tableid,sp->dp->numhands-1,sp->dp->N)); else return(pangea_dispsummary(sp,juint(json,"verbose"),sp->dp->summary,sp->dp->summarysize,tableid,juint(json,"handid"),sp->dp->N)); } return(clonestr("{\"error\":\"cant find tableid\"}")); } char *pangea_buyin(uint64_t my64bits,uint64_t tableid,cJSON *json) { struct pangea_info *sp; uint32_t buyin,vout; uint64_t amount = 0; char hex[1024],jsonstr[1024],*txidstr,*destaddr; if ( (sp= pangea_find64(tableid,my64bits)) != 0 && sp->dp != 0 && sp->tp != 0 && (amount= j64bits(json,"amount")) != 0 ) { buyin = (uint32_t)(amount / sp->dp->bigblind); PostMessage("buyin.%u amount %.8f -> %.8f\n",buyin,dstr(amount),dstr(buyin * sp->bigblind)); if ( buyin >= sp->dp->minbuyin && buyin <= sp->dp->maxbuyin ) { sp->balances[pangea_ind(sp,sp->myslot)] = amount; if ( (txidstr= jstr(json,"txidstr")) != 0 && (destaddr= jstr(json,"msigaddr")) != 0 && strcmp(destaddr,sp->multisigaddr) == 0 ) { vout = juint(json,"vout"); sprintf(jsonstr,"{\"txid\":\"%s\",\"vout\":%u,\"msig\":\"%s\",\"amount\":%.8f}",txidstr,vout,sp->multisigaddr,dstr(amount)); pangea_sendcmd(hex,&sp->tp->hn,"addfunds",-1,(void *)jsonstr,(int32_t)strlen(jsonstr)+1,pangea_ind(sp,sp->myslot),-1); } else pangea_sendcmd(hex,&sp->tp->hn,"addfunds",-1,(void *)&amount,sizeof(amount),pangea_ind(sp,sp->myslot),-1); //pangea_sendcmd(hex,&sp->tp->hn,"addfunds",0,(void *)&amount,sizeof(amount),pangea_ind(sp,sp->myslot),-1); return(clonestr("{\"result\":\"buyin sent\"}")); } else { PostMessage("buyin.%d vs (%d %d)\n",buyin,sp->dp->minbuyin,sp->dp->maxbuyin); return(clonestr("{\"error\":\"buyin too small or too big\"}")); } } return(clonestr("{\"error\":\"cant buyin unless you are part of the table\"}")); } char *pangea_mode(uint64_t my64bits,uint64_t tableid,cJSON *json) { struct pangea_info *sp; char *chatstr,hex[8192]; int32_t i; uint64_t pm; if ( jobj(json,"automuck") != 0 ) { if ( tableid == 0 ) Showmode = juint(json,"automuck"); else if ( (sp= pangea_find64(tableid,my64bits)) != 0 && sp->priv != 0 ) sp->priv->automuck = juint(json,"automuck"); else return(clonestr("{\"error\":\"automuck not tableid or sp->priv\"}")); return(clonestr("{\"result\":\"set automuck mode\"}")); } else if ( jobj(json,"autofold") != 0 ) { if ( tableid == 0 ) Autofold = juint(json,"autofold"); else if ( (sp= pangea_find64(tableid,my64bits)) != 0 && sp->priv != 0 ) sp->priv->autofold = juint(json,"autofold"); else return(clonestr("{\"error\":\"autofold not tableid or sp->priv\"}")); return(clonestr("{\"result\":\"set autofold mode\"}")); } else if ( (sp= pangea_find64(tableid,my64bits)) != 0 && (chatstr= jstr(json,"chat")) != 0 && strlen(chatstr) < 256 ) { if ( 0 && (pm= j64bits(json,"pm")) != 0 ) { for (i=0; inumaddrs; i++) if ( sp->addrs[i] == pm ) break; if ( i == sp->numaddrs ) return(clonestr("{\"error\":\"specified pm destination not at table\"}")); } else i = -1; pangea_sendcmd(hex,&sp->tp->hn,"chat",i,(void *)chatstr,(int32_t)strlen(chatstr)+1,pangea_ind(sp,sp->myslot),-1); return(clonestr("{\"result\":\"chat message sent\"}")); } return(clonestr("{\"error\":\"unknown pangea mode\"}")); } char *pangea_univ(uint8_t *mypriv,cJSON *json) { char *addrtypes[][3] = { {"BTC","0","80"}, {"LTC","48"}, {"BTCD","60","bc"}, {"DOGE","30"}, {"VRC","70"}, {"OPAL","115"}, {"BITS","25"} }; char *wipstr,*coin,*coinaddr,pubkeystr[67],rsaddr[64],destaddr[64],wifbuf[128]; uint8_t priv[32],pub[33],addrtype; int32_t i; uint64_t nxt64bits; cJSON *retjson,*item; PostMessage("inside rosetta\n"); if ( (coin= jstr(json,"coin")) != 0 ) { if ( (wipstr= jstr(json,"wif")) != 0 || (wipstr= jstr(json,"wip")) != 0 ) { PostMessage("got wip.(%s)\n",wipstr); btc_wip2priv(priv,wipstr); } else if ( (coinaddr= jstr(json,"addr")) != 0 ) { if ( getprivkey(priv,coin,coinaddr) < 0 ) return(clonestr("{\"error\":\"cant get privkey\"}")); } } else memcpy(priv,mypriv,sizeof(priv)); btc_priv2pub(pub,priv); init_hexbytes_noT(pubkeystr,pub,33); PostMessage("pubkey.%s\n",pubkeystr); retjson = cJSON_CreateObject(); jaddstr(retjson,"btcpubkey",pubkeystr); for (i=0; isleepmillis = 1; //if ( PANGEA_MAXTHREADS > 1 && PANGEA_MAXTHREADS <= 9 ) // numthreads = PANGEA_MAXTHREADS; //else PostMessage("pangeatest\n"); if ( PANGEA_MAXTHREADS == 0 ) PANGEA_MAXTHREADS = numthreads; else numthreads = PANGEA_MAXTHREADS; if ( plugin->transport[0] == 0 ) strcpy(plugin->transport,TEST_TRANSPORT); if ( plugin->ipaddr[0] == 0 ) strcpy(plugin->ipaddr,"127.0.0.1"); if ( plugin->pangeaport == 0 ) plugin->pangeaport = 12343; PostMessage("pangea numthreads.%d\n",numthreads); if ( (clients= calloc(numthreads,sizeof(*clients))) == 0 ) { PostMessage("pangea_test: unexpected out of mem\n"); return; } for (threadid=0; threadidthreadid = threadid; if ( threadid != 0 ) { char hexstr[65]; uint32_t tmp = threadid + 4; tp->nxt64bits = conv_NXTpassword(privkey.bytes,pubkey.bytes,(void *)&tmp,sizeof(tmp)); init_hexbytes_noT(hexstr,pubkey.bytes,sizeof(pubkey)); printf("NXT.%llu pubkey.%s\n",(long long)tp->nxt64bits,hexstr); } else { tp->nxt64bits = plugin->nxt64bits; memcpy(privkey.bytes,plugin->mypriv,32); memcpy(pubkey.bytes,plugin->mypub,32); } if ( threadid == 0 ) { if ( (srv= hostnet777_server(privkey,pubkey,0,0,0,numthreads)) == 0 ) { PostMessage("cant create hostnet777 server\n"); free(tp); return; } tp->hn.server = srv; clients[0] = (void *)srv; slot = threadid; // srv->H.privkey = privkey, srv->H.pubkey = pubkey; } else { if ( (slot= hostnet777_register(srv,pubkey,-1)) >= 0 && slot == threadid ) { if ( (clients[threadid]= hostnet777_client(privkey,pubkey,srv->ep.endpoint,slot)) == 0 ) PostMessage("error creating clients[%d]\n",threadid); else { tp->hn.client = clients[threadid]; //tp->hn.client->H.privkey = privkey, tp->hn.client->H.pubkey = pubkey; //if ( portable_thread_create((void *)hostnet777_idler,hn) == 0 ) // PostMessage("error launching clients[%d] thread\n",threadid); } } else PostMessage("error slot.%d != threadid.%d\n",slot,threadid); } if ( clients[threadid] != 0 ) PostMessage("%llu: slot.%d client.%p -> %llu pubkey.%llx/%llx privkey.%llx/%llx\n",(long long)tp->nxt64bits,slot,clients[threadid],(long long)clients[threadid]->H.nxt64bits,(long long)clients[threadid]->H.pubkey.txid,(long long)pubkey.txid,(long long)clients[threadid]->H.privkey.txid,(long long)privkey.txid); THREADS[threadid] = tp; } bids = cJSON_CreateArray(); PostMessage("numthreads.%d notabot.%d\n",numthreads,plugin->notabot);//, getchar(); for (i=0; inotabot != numthreads ) { if ( i != plugin->notabot ) jaddnum(walletitem,"isbot",1); } jadd64bits(walletitem,"bigblind",bigblind); jadd64bits(walletitem,"ante",ante); jaddnum(walletitem,"rakemillis",rakemillis); //jadd64bits(walletitem,"balance",bigblind * 100); jadd64bits(item,"offerNXT",THREADS[i]->nxt64bits); jadd(item,"wallet",walletitem); jaddi(bids,item); } jadd(testjson,"bids",bids); jadd64bits(testjson,"offerNXT",THREADS[0]->nxt64bits); jadd64bits(testjson,"bigblind",bigblind); jadd64bits(testjson,"ante",ante); jaddnum(testjson,"rakemillis",rakemillis); PostMessage("TEST.(%s)\n",jprint(testjson,0)); pangea_start(plugin,retbuf,"BTCD",0,bigblind,ante,rakemillis,i,0,0,testjson); free_json(testjson); testjson = cJSON_Parse(retbuf); //PostMessage("BROADCAST.(%s)\n",retbuf); for (threadid=1; threadidnxt64bits,THREADS[threadid]->hn.client->H.privkey,THREADS[threadid]->hn.client->H.pubkey,0,0,0,0,0,rakemillis); for (threadid=0; threadidhn.client->H.pubdata; if ( (sp= dp->table) == 0 ) PostMessage("pangea_test: null table\n"); for (j=0; jbalances[j] = 1000 * SATOSHIDEN; PostMessage("T%d: set balances sp.%p\n",threadid,sp); } //for (threadid=0; threadidhn) == 0 ) // PostMessage("error launching server thread\n"); //tp = THREADS[0]; //pangea_newdeck(&tp->hn); free(clients); } int32_t PLUGNAME(_process_json)(char *forwarder,char *sender,int32_t valid,struct plugin_info *plugin,uint64_t tag,char *retbuf,int32_t maxlen,char *jsonstr,cJSON *json,int32_t initflag,char *tokenstr) { char *resultstr,*methodstr,*base,*retstr = 0; int32_t maxplayers,tmp; cJSON *argjson; retbuf[0] = 0; PostMessage("<<<<<<<<<<<< INSIDE PANGEA! process %s (%s) forwarder.(%s) sender.(%s)\n",plugin->name,jsonstr,forwarder,sender); if ( initflag > 0 ) { randombytes((uint8_t *)&tmp,sizeof(tmp)), srand(tmp); uint64_t conv_NXTpassword(unsigned char *mysecret,unsigned char *mypublic,uint8_t *pass,int32_t passlen); //PANGEA.readyflag = 1; plugin->sleepmillis = 10; plugin->allowremote = 1; argjson = cJSON_Parse(jsonstr); plugin->nxt64bits = set_account_NXTSECRET(plugin->mypriv,plugin->mypub,plugin->NXTACCT,plugin->NXTADDR,plugin->NXTACCTSECRET,sizeof(plugin->NXTACCTSECRET),argjson,0,0,0); free_json(argjson); PostMessage("(%s) pangea.my64bits %llu ipaddr.%s mypriv.%02x mypub.%02x\n",jprint(json,0),(long long)plugin->nxt64bits,plugin->ipaddr,plugin->mypriv[0],plugin->mypub[0]); PANGEA_MAXTHREADS = juint(json,"pangeatest"); plugin->notabot = juint(json,"notabot"); if ( PANGEA_MAXTHREADS != 0 ) { PostMessage("notabot.%d launch pangea_test\n",plugin->notabot); //pangea_test(plugin); portable_thread_create((void *)pangea_test,plugin);//,9,SATOSHIDEN,SATOSHIDEN/10,10); } PostMessage("initialized PANGEA\n"); if ( 0 ) { int32_t i; char str[8]; for (i=0; i<52; i++) { cardstr(str,i); PostMessage("(%d %s) ",i,str); } PostMessage("cards\n"); } } else { if ( plugin_result(retbuf,json,tag) > 0 ) return((int32_t)strlen(retbuf)); methodstr = jstr(json,"method"); resultstr = jstr(json,"result"); if ( methodstr == 0 || methodstr[0] == 0 ) { PostMessage("(%s) has not method\n",jsonstr); return(0); } else if ( resultstr != 0 && strcmp(resultstr,"registered") == 0 ) { plugin->registered = 1; strcpy(retbuf,"{\"result\":\"activated\"}"); } else if ( strcmp(methodstr,"newtable") == 0 ) retstr = pangea_newtable(juint(json,"threadid"),json,plugin->nxt64bits,*(bits256 *)plugin->mypriv,*(bits256 *)plugin->mypub,plugin->transport,plugin->ipaddr,plugin->pangeaport,juint(json,"minbuyin"),juint(json,"maxbuyin"),juint(json,"rakemillis")); else if ( sender == 0 || sender[0] == 0 ) { if ( strcmp(methodstr,"start") == 0 ) { strcpy(retbuf,"{\"result\":\"start issued\"}"); if ( (base= jstr(json,"base")) != 0 ) { if ( (maxplayers= juint(json,"maxplayers")) < 2 ) maxplayers = 2; else if ( maxplayers > CARDS777_MAXPLAYERS ) maxplayers = CARDS777_MAXPLAYERS; if ( jstr(json,"resubmit") == 0 ) sprintf(retbuf,"{\"resubmit\":[{\"method\":\"start\"}, {\"bigblind\":\"%llu\"}, {\"ante\":\"%llu\"}, {\"rakemillis\":\"%u\"}, {\"maxplayers\":%d}, {\"minbuyin\":%d}, {\"maxbuyin\":%d}],\"pluginrequest\":\"SuperNET\",\"plugin\":\"InstantDEX\",\"method\":\"orderbook\",\"base\":\"%s\",\"exchange\":\"pangea\",\"allfields\":1}",(long long)j64bits(json,"bigblind"),(long long)j64bits(json,"ante"),juint(json,"rakemillis"),maxplayers,juint(json,"minbuyin"),juint(json,"maxbuyin"),jstr(json,"base")!=0?jstr(json,"base"):"BTCD"); else if ( pangea_start(plugin,retbuf,base,0,j64bits(json,"bigblind"),j64bits(json,"ante"),juint(json,"rakemillis"),maxplayers,juint(json,"minbuyin"),juint(json,"maxbuyin"),json) < 0 ) ; } else strcpy(retbuf,"{\"error\":\"no base specified\"}"); } else if ( strcmp(methodstr,"status") == 0 ) retstr = pangea_status(plugin->nxt64bits,j64bits(json,"tableid"),json); } //else if ( strcmp(methodstr,"turn") == 0 ) // retstr = pangea_input(plugin->nxt64bits,j64bits(json,"tableid"),json); } return(plugin_copyretstr(retbuf,maxlen,retstr)); } char *Pangea_bypass(uint64_t my64bits,uint8_t myprivkey[32],cJSON *json) { char *methodstr,*passphrase,*retstr = 0; if ( (methodstr= jstr(json,"method")) != 0 ) { if ( strcmp(methodstr,"turn") == 0 ) retstr = pangea_input(my64bits,j64bits(json,"tableid"),json); else if ( strcmp(methodstr,"status") == 0 ) retstr = pangea_status(my64bits,j64bits(json,"tableid"),json); else if ( strcmp(methodstr,"mode") == 0 ) retstr = pangea_mode(my64bits,j64bits(json,"tableid"),json); else if ( strcmp(methodstr,"rosetta") == 0 ) retstr = pangea_univ(myprivkey,json); else if ( strcmp(methodstr,"buyin") == 0 ) retstr = pangea_buyin(my64bits,j64bits(json,"tableid"),json); else if ( strcmp(methodstr,"history") == 0 ) retstr = pangea_history(my64bits,j64bits(json,"tableid"),json); else if ( strcmp(methodstr,"rates") == 0 ) retstr = peggyrates(0,jstr(json,"name")); else if ( strcmp(methodstr,"pangeatest") == 0 ) { int32_t n; n = juint(json,"numplayers"); if ( n >= 2 && n <= 9 ) retstr = SuperNET_setconf(methodstr,n); else return(clonestr("{\"error\":\"invalid numplayers\"}")); } else if ( strcmp(methodstr,"changenum") == 0 ) { char *fieldstr; if ( (fieldstr= jstr(json,"fieldname")) != 0 ) retstr = SuperNET_setconf(fieldstr,juint(json,"val")); else return(clonestr("{\"error\":\"no fieldname\"}")); } else if ( strcmp(methodstr,"changefield") == 0 ) { char *fieldstr; if ( (fieldstr= jstr(json,"fieldname")) != 0 ) retstr = SuperNET_setconfstr(fieldstr,jstr(json,"valstr")); else return(clonestr("{\"error\":\"no fieldname\"}")); } else if ( strcmp(methodstr,"notabot") == 0 ) { int32_t n; n = juint(json,"val"); if ( n == 0 || n == -1 ) retstr = SuperNET_setconf(methodstr,n); else return(clonestr("{\"error\":\"invalid notabot\"}")); } else if ( strcmp(methodstr,"clearconf") == 0 ) { if ( SuperNET_saveconf("{\"secret\":\"randvals\"}") == 0 ) return(clonestr("{\"result\":\"SuperNET.conf restored to defaults\"}")); else return(clonestr("{\"error\":\"SuperNET.conf couldnt be cleared\"}")); } else if ( strcmp(methodstr,"secret") == 0 && (passphrase= jstr(json,"passphrase")) != 0 ) { char buf[1024],rsaddr[64]; uint64_t nxt64bits; bits256 pubkey,privkey; sprintf(buf,"{\"secret\":\"%s\"}",passphrase); if ( SuperNET_saveconf(buf) == 0 ) { nxt64bits = conv_NXTpassword(privkey.bytes,pubkey.bytes,(void *)passphrase,(int32_t)strlen(passphrase)); RS_encode(rsaddr,nxt64bits); sprintf(buf,"{\"result\":\"success\",\"NXT\":\"%llu\",\"RS\":\"%s\"}",(long long)nxt64bits,rsaddr); return(clonestr(buf)); } else return(clonestr("{\"error\":\"couldnt sent new passphrase\"}")); } } // ./BitcoinDarkd SuperNET '{"agent":"pangea","method":"pangeatest","numplayers":2}' // ./BitcoinDarkd SuperNET '{"agent":"pangea","method":"notabot","val":-1}' // ./BitcoinDarkd SuperNET '{"agent":"pangea","method":"clearconf"}' // ./BitcoinDarkd SuperNET '{"agent":"pangea","method":"secret","passphrase":"password"}' return(retstr); } #endif