You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1630 lines
71 KiB

9 years ago
/******************************************************************************
* Copyright © 2014-2016 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. *
* *
******************************************************************************/
9 years ago
// selftest supports against allpairs list
9 years ago
#include "exchanges777.h"
9 years ago
struct instantdex_stateinfo *BTC_states; int32_t BTC_numstates;
9 years ago
9 years ago
int64_t instantdex_BTCsatoshis(int64_t price,int64_t volume)
9 years ago
{
9 years ago
if ( volume > price )
return(price * dstr(volume));
else return(dstr(price) * volume);
}
9 years ago
9 years ago
int64_t instantdex_insurance(struct iguana_info *coin,int64_t amount)
9 years ago
{
9 years ago
return(amount * INSTANTDEX_INSURANCERATE + coin->chain->txfee); // insurance prevents attack
}
9 years ago
9 years ago
void instantdex_swapfree(struct instantdex_accept *A,struct bitcoin_swapinfo *swap)
9 years ago
{
9 years ago
if ( A != 0 )
free(A);
if ( swap != 0 )
{
if ( swap->deposit != 0 )
free(swap->deposit);
if ( swap->payment != 0 )
free(swap->payment);
if ( swap->altpayment != 0 )
free(swap->altpayment);
9 years ago
if ( swap->myfee != 0 )
free(swap->myfee);
if ( swap->otherfee != 0 )
free(swap->otherfee);
9 years ago
}
}
9 years ago
int32_t instantdex_unbasebits(char *base,uint64_t basebits)
{
char tmp[9];
unstringbits(tmp,basebits);
if ( iguana_coinfind(tmp) == 0 )
{
sprintf(base,"%lld",(long long)basebits);
return(1);
}
else
{
strcmp(base,tmp);
return(0);
}
}
uint64_t instantdex_basebits(char *base)
{
if ( is_decimalstr(base) != 0 )
return(calc_nxt64bits(base));
else return(stringbits(base));
}
uint64_t instantdex_decodehash(char *base,char *rel,int64_t *pricep,uint64_t *accountp,bits256 encodedhash)
{
int32_t i; uint64_t offerid;
base[4] = rel[4] = 0;
for (i=0; i<4; i++)
{
base[i] = encodedhash.bytes[8 + i];
rel[i] = encodedhash.bytes[12 + i];
}
iguana_rwnum(0,(void *)&encodedhash.ulongs[2],sizeof(uint64_t),pricep);
iguana_rwnum(0,(void *)&encodedhash.ulongs[3],sizeof(uint64_t),accountp);
iguana_rwnum(0,(void *)&encodedhash.ulongs[0],sizeof(uint64_t),&offerid);
return(encodedhash.ulongs[0]);
}
bits256 instantdex_encodehash(char *base,char *rel,int64_t price,uint64_t orderid,uint64_t account)
{
bits256 encodedhash; int32_t i; char _base[4],_rel[4];
iguana_rwnum(1,(void *)&encodedhash.ulongs[0],sizeof(uint64_t),&orderid);
memset(_base,0,sizeof(_base));
memset(_rel,0,sizeof(_rel));
strncpy(_base,base,4);
strncpy(_rel,rel,4);
for (i=0; i<4; i++)
{
encodedhash.bytes[8 + i] = _base[i];
encodedhash.bytes[12 + i] = _rel[i];
}
iguana_rwnum(1,(void *)&encodedhash.ulongs[2],sizeof(uint64_t),&price);
iguana_rwnum(1,(void *)&encodedhash.ulongs[3],sizeof(uint64_t),&account);
return(encodedhash);
}
9 years ago
cJSON *instantdex_defaultprocess(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
9 years ago
{
uint8_t *serdata = *serdatap; int32_t serdatalen = *serdatalenp;
9 years ago
*serdatap = 0, *serdatalenp = 0;
if ( serdata != 0 && serdatalen > 0 )
{
serdata[serdatalen-1] = 0;
}
return(newjson);
}
9 years ago
9 years ago
cJSON *instantdex_defaulttimeout(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp)
9 years ago
{
9 years ago
uint8_t *serdata = *serdatap; int32_t serdatalen = *serdatalenp;
9 years ago
*serdatap = 0, *serdatalenp = 0;
if ( serdata != 0 && serdatalen > 0 )
{
serdata[serdatalen-1] = 0;
}
return(newjson);
}
9 years ago
struct instantdex_stateinfo instantdex_errorstate = { "error", 0,0, instantdex_defaultprocess, instantdex_defaulttimeout };
struct instantdex_stateinfo instantdex_timeoutstate = { "timeout", 1,0, instantdex_defaultprocess, instantdex_defaulttimeout };
9 years ago
struct instantdex_stateinfo *instantdex_statefind(struct instantdex_stateinfo *states,int32_t numstates,char *statename)
{
int32_t i; struct instantdex_stateinfo *state = 0;
if ( states != 0 && statename != 0 && numstates > 0 )
{
for (i=0; i<numstates; i++)
{
if ( (state= &states[i]) != 0 && strcmp(state->name,statename) == 0 )
return(state);
}
}
return(0);
}
9 years ago
void instantdex_stateinit(struct instantdex_stateinfo *states,int32_t numstates,struct instantdex_stateinfo *state,char *name,char *errorstr,char *timeoutstr,void *process_func,void *timeout_func)
{
struct instantdex_stateinfo *timeoutstate,*errorstate;
memset(state,0,sizeof(*state));
strcpy(state->name,name);
if ( (errorstate= instantdex_statefind(states,numstates,errorstr)) == 0 )
errorstate = &instantdex_errorstate;
9 years ago
state->errorind = errorstate->ind;
9 years ago
if ( (timeoutstate= instantdex_statefind(states,numstates,timeoutstr)) == 0 )
timeoutstate = &instantdex_timeoutstate;
9 years ago
else printf("TS.%s ",timeoutstr);
state->timeoutind = timeoutstate->ind;
9 years ago
if ( (state->process= process_func) == 0 )
state->process = instantdex_defaultprocess;
if ( (state->timeout= timeout_func) == 0 )
state->timeout = instantdex_defaulttimeout;
}
9 years ago
struct instantdex_stateinfo *instantdex_statecreate(struct instantdex_stateinfo *states,int32_t *numstatesp,char *name,cJSON *(*process_func)(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp),cJSON *(*timeout_func)(struct supernet_info *myinfo,struct exchange_info *exchange,struct bitcoin_swapinfo *swap,cJSON *argjson,cJSON *newjson,uint8_t **serdatap,int32_t *serdatalenp),char *timeoutstr,char *errorstr,int32_t initialstate)
9 years ago
{
9 years ago
struct instantdex_stateinfo S,*state = 0;
9 years ago
if ( (state= instantdex_statefind(states,*numstatesp,name)) == 0 )
{
states = realloc(states,sizeof(*states) * (*numstatesp + 1));
state = &states[*numstatesp];
9 years ago
instantdex_stateinit(states,*numstatesp,state,name,errorstr,timeoutstr,process_func,timeout_func);
9 years ago
state->initialstate = initialstate;
9 years ago
printf("STATES[%d] %s %p %p %d %d\n",*numstatesp,state->name,state->process,state->timeout,state->timeoutind,state->errorind);
state->ind = (*numstatesp)++;
9 years ago
}
else
{
instantdex_stateinit(states,*numstatesp,&S,name,errorstr,timeoutstr,process_func,timeout_func);
9 years ago
S.ind = state->ind;
9 years ago
S.initialstate = initialstate;
9 years ago
if ( memcmp(&S,state,sizeof(S) - sizeof(void *) - sizeof(int)) != 0 )
{
int32_t i;
for (i=0; i<sizeof(S); i++)
printf("%02x ",((uint8_t *)&S)[i]);
printf("S\n");
for (i=0; i<sizeof(S); i++)
printf("%02x ",((uint8_t *)state)[i]);
printf("state\n");
printf("%s %p %p %d %d vs %s %p %p %d %d\n",state->name,state->process,state->timeout,state->timeoutind,state->errorind,S.name,S.process,S.timeout,S.timeoutind,S.errorind);
9 years ago
printf("statecreate error!!! (%s) already exists\n",name);
9 years ago
}
9 years ago
}
9 years ago
return(states);
9 years ago
}
struct instantdex_event *instantdex_addevent(struct instantdex_stateinfo *states,int32_t numstates,char *statename,char *cmdstr,char *sendcmd,char *nextstatename)
{
struct instantdex_stateinfo *nextstate,*state;
if ( (state= instantdex_statefind(states,numstates,statename)) != 0 && (nextstate= instantdex_statefind(states,numstates,nextstatename)) != 0 )
{
if ( (state->events= realloc(state->events,(state->numevents + 1) * sizeof(*state->events))) != 0 )
{
9 years ago
memset(&state->events[state->numevents],0,sizeof(state->events[state->numevents]));
9 years ago
strcpy(state->events[state->numevents].cmdstr,cmdstr);
9 years ago
if ( sendcmd != 0 )
strcpy(state->events[state->numevents].sendcmd,sendcmd);
9 years ago
state->events[state->numevents].nextstateind = nextstate->ind;
9 years ago
state->numevents++;
}
return(state->events);
}
else
{
9 years ago
int32_t i;
for (i=0; i<numstates; i++)
printf("%s[%d] ",states[i].name,i);
9 years ago
printf("cant add event (%s -> %s) without existing state and nextstate\n",statename,nextstatename);
9 years ago
exit(-1);
9 years ago
return(0);
}
}
double instantdex_FSMtest(struct instantdex_stateinfo *states,int32_t numstates,int32_t maxiters)
9 years ago
{
int32_t i,most,r,r2,n,m=0,initials[100],nextstate=-1;
struct instantdex_stateinfo *state; struct instantdex_event *event; double sum = 0.;
if ( maxiters < 1 )
maxiters = 1;
for (i=n=most=0; i<numstates; i++)
if ( states[i].initialstate > 0 )
{
printf("initialstate[%d] %d %s\n",i,states[i].initialstate,states[i].name);
9 years ago
initials[n++] = i;
}
9 years ago
if ( n > 0 && n < sizeof(initials)/sizeof(*initials) )
{
for (i=0; i<maxiters; i++)
{
r = rand() % n;
state = &states[initials[r]];
if ( state->name[0] == 0 || state->ind >= numstates )
{
printf("illegal state.(%s) %d? ind.%d >= numstates.%d\n",state->name,nextstate,state->ind,numstates);
break;
}
9 years ago
m = 0;
while ( m++ < 1000 && state->initialstate >= 0 && state->numevents != 0 )
9 years ago
{
if ( (i % 1000000) == 0 )
fprintf(stderr,"%s ",state->name);
r2 = rand() % state->numevents;
event = &state->events[r2];
if ( (nextstate= event->nextstateind) < 0 )
break;
if ( event->nextstateind >= numstates )
{
printf("nextstateind overflow? %d vs %d\n",event->nextstateind,numstates);
9 years ago
break;
}
9 years ago
state = &states[event->nextstateind];
}
if ( m > most )
most = m;
sum += m;
if ( (i % 1000000) == 0 )
fprintf(stderr,"reached %s m.%d events most.%d ave %.2f\n",state->name,m,most,sum/(i+1));
9 years ago
}
}
fprintf(stderr," most.%d ave %.2f\n",most,sum/(i+1));
return(sum / maxiters);
9 years ago
}
9 years ago
void instantdex_FSMinit()
{
if ( BTC_states == 0 )
BTC_states = BTC_initFSM(&BTC_numstates);
}
9 years ago
cJSON *InstantDEX_argjson(char *reference,char *message,char *othercoinaddr,char *otherNXTaddr,int32_t iter,int32_t val,int32_t val2)
9 years ago
{
cJSON *argjson = cJSON_CreateObject();
if ( reference != 0 )
jaddstr(argjson,"refstr",reference);
if ( message != 0 && message[0] != 0 )
jaddstr(argjson,"message",message);
9 years ago
if ( othercoinaddr != 0 && othercoinaddr[0] != 0 )
jaddstr(argjson,"othercoinaddr",othercoinaddr);
if ( otherNXTaddr != 0 && otherNXTaddr[0] != 0 )
jaddstr(argjson,"otherNXTaddr",otherNXTaddr);
//jaddbits256(argjson,"basetxid",basetxid);
//jaddbits256(argjson,"reltxid",reltxid);
9 years ago
if ( iter != 3 )
{
if ( val == 0 )
val = INSTANTDEX_DURATION;
jaddnum(argjson,"duration",val);
jaddnum(argjson,"flags",val2);
}
else
{
if ( val > 0 )
jaddnum(argjson,"baseheight",val);
if ( val2 > 0 )
jaddnum(argjson,"relheight",val2);
}
return(argjson);
}
9 years ago
struct instantdex_msghdr *instantdex_msgcreate(struct supernet_info *myinfo,struct instantdex_msghdr *msg,int32_t datalen)
{
bits256 otherpubkey; uint64_t signerbits; uint32_t timestamp; uint8_t buf[sizeof(msg->sig)],*data;
memset(&msg->sig,0,sizeof(msg->sig));
datalen += (int32_t)(sizeof(*msg) - sizeof(msg->sig));
data = (void *)((long)msg + sizeof(msg->sig));
otherpubkey = acct777_msgpubkey(data,datalen);
timestamp = (uint32_t)time(NULL);
acct777_sign(&msg->sig,myinfo->privkey,otherpubkey,timestamp,data,datalen);
9 years ago
//printf("signed datalen.%d allocsize.%d crc.%x\n",datalen,msg->sig.allocsize,calc_crc32(0,data,datalen));
9 years ago
if ( (signerbits= acct777_validate(&msg->sig,acct777_msgprivkey(data,datalen),msg->sig.pubkey)) != 0 )
{
9 years ago
//int32_t i;
9 years ago
//char str[65],str2[65];
9 years ago
//for (i=0; i<datalen; i++)
// printf("%02x",data[i]);
9 years ago
//printf(">>>>>>>>>>>>>>>> validated [%ld] len.%d (%s + %s)\n",(long)data-(long)msg,datalen,bits256_str(str,acct777_msgprivkey(data,datalen)),bits256_str(str2,msg->sig.pubkey));
9 years ago
memset(buf,0,sizeof(buf));
acct777_rwsig(1,buf,&msg->sig);
memcpy(&msg->sig,buf,sizeof(buf));
return(msg);
} else printf("error validating instantdex msg\n");
return(0);
}
9 years ago
bits256 instantdex_rwoffer(int32_t rwflag,int32_t *lenp,uint8_t *serialized,struct instantdex_offer *offer)
9 years ago
{
9 years ago
bits256 orderhash; int32_t len = 0;
9 years ago
if ( rwflag == 1 )
9 years ago
{
9 years ago
vcalc_sha256(0,orderhash.bytes,(void *)offer,sizeof(*offer));
9 years ago
/*int32_t i;
9 years ago
for (i=0; i<sizeof(*offer); i++)
printf("%02x ",((uint8_t *)offer)[i]);
printf("rwoffer offer\n");*/
9 years ago
}
else
{
memset(offer,0,sizeof(*offer));
9 years ago
}
9 years ago
len += iguana_rwstr(rwflag,&serialized[len],sizeof(offer->base),offer->base);
len += iguana_rwstr(rwflag,&serialized[len],sizeof(offer->rel),offer->rel);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(offer->price64),&offer->price64);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(offer->basevolume64),&offer->basevolume64);
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(offer->account),&offer->account);
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(offer->expiration),&offer->expiration);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(offer->nonce),&offer->nonce);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(offer->myside),&offer->myside);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(offer->acceptdir),&offer->acceptdir);
9 years ago
if ( rwflag == 0 )
9 years ago
{
9 years ago
vcalc_sha256(0,orderhash.bytes,(void *)offer,sizeof(*offer));
9 years ago
/*int32_t i;
9 years ago
for (i=0; i<len; i++)
printf("%02x ",serialized[i]);
printf("read rwoffer serialized\n");
for (i=0; i<sizeof(*offer); i++)
printf("%02x ",((uint8_t *)offer)[i]);
printf("rwoffer offer\n");*/
9 years ago
}
9 years ago
/*else
9 years ago
{
int32_t i;
for (i=0; i<len; i++)
printf("%02x ",serialized[i]);
printf("wrote rwoffer serialized\n");
}*/
9 years ago
*lenp = len;
9 years ago
return(orderhash);
9 years ago
}
9 years ago
char *instantdex_sendcmd(struct supernet_info *myinfo,struct instantdex_offer *offer,cJSON *argjson,char *cmdstr,bits256 desthash,int32_t hops,void *extraser,int32_t extralen,struct iguana_peer *addr)
9 years ago
{
9 years ago
char *reqstr,*hexstr,*retstr; struct instantdex_msghdr *msg; bits256 orderhash; struct iguana_info *coin; int32_t i,olen,slen,datalen,max=-1; uint8_t serialized[sizeof(*offer) + sizeof(struct iguana_msghdr) + 4096 + INSTANTDEX_DECKSIZE*33]; uint64_t nxt64bits;
category_subscribe(myinfo,myinfo->instantdex_category,GENESIS_PUBKEY);
9 years ago
jaddstr(argjson,"cmd",cmdstr);
jaddstr(argjson,"agent","SuperNET");
jaddstr(argjson,"method","DHT");
9 years ago
jaddstr(argjson,"handle",myinfo->handle);
jaddbits256(argjson,"categoryhash",myinfo->instantdex_category);
9 years ago
jaddbits256(argjson,"traderpub",myinfo->myaddr.persistent);
9 years ago
orderhash = instantdex_rwoffer(1,&olen,serialized,offer);
9 years ago
if ( 1 )
9 years ago
{
struct instantdex_offer checkoffer; bits256 checkhash; int32_t checklen;
checkhash = instantdex_rwoffer(0,&checklen,serialized,&checkoffer);
9 years ago
if ( checkhash.txid != orderhash.txid )
{
for (i=0; i<sizeof(checkoffer); i++)
printf("%02x ",((uint8_t *)&checkoffer)[i]);
printf("checklen.%d checktxid.%llu\n",checklen,(long long)checkhash.txid);
}
9 years ago
}
9 years ago
jadd64bits(argjson,"id",orderhash.txid);
9 years ago
nxt64bits = acct777_nxt64bits(myinfo->myaddr.persistent);
9 years ago
reqstr = jprint(argjson,0);
9 years ago
slen = (int32_t)(strlen(reqstr) + 1);
9 years ago
datalen = (int32_t)slen + extralen + olen;
9 years ago
msg = calloc(1,datalen + sizeof(*msg));
9 years ago
for (i=0; i<sizeof(msg->cmd); i++)
if ( (msg->cmd[i]= cmdstr[i]) == 0 )
break;
9 years ago
memcpy(msg->serialized,reqstr,slen);
memcpy(&msg->serialized[slen],serialized,olen);
9 years ago
//printf("extralen.%d datalen.%d slen.%d olen.%d\n",extralen,datalen,slen,olen);
9 years ago
if ( extralen > 0 )
memcpy(&msg->serialized[slen + olen],extraser,extralen);
9 years ago
free(reqstr);
9 years ago
if ( instantdex_msgcreate(myinfo,msg,datalen) != 0 )
9 years ago
{
9 years ago
printf(">>>>>>>>>>>> instantdex send.(%s) datalen.%d allocsize.%d crc.%x\n",cmdstr,datalen,msg->sig.allocsize,calc_crc32(0,(void *)((long)msg + 8),datalen-8));
9 years ago
if ( addr != 0 )
9 years ago
{
9 years ago
memset(serialized,0,sizeof(struct iguana_msghdr));
memcpy(&serialized[sizeof(struct iguana_msghdr)],(uint8_t *)msg,msg->sig.allocsize);
9 years ago
if ( (coin= iguana_coinfind("BTCD")) != 0 )//&& (max= coin->peers.numranked) > 0 )
9 years ago
{
9 years ago
iguana_queue_send(coin,addr,0,serialized,"InstantDEX",msg->sig.allocsize,0,0);
/*r = (rand() % max);
9 years ago
for (i=0; i<max; i++)
{
j = (i + r) % max;
if ( (addr= coin->peers.ranked[j]) != 0 && addr->supernet != 0 && addr->usock >= 0 )
{
printf("send.%d to (%s)\n",(int32_t)msg->sig.allocsize,addr->ipaddr);
iguana_queue_send(coin,addr,0,serialized,"InstantDEX",msg->sig.allocsize,0,0);
if ( --hops <= 0 )
break;
} //else printf("skip.%d addr.%p (%s) max.%d hops.%d\n",j,addr,addr!=0?addr->ipaddr:"",max,hops);
}*/
9 years ago
} else printf("cant find coin.%p or no ranked.%d\n",coin,max);
}
else
{
9 years ago
if ( (hexstr= malloc(msg->sig.allocsize*2 + 1)) != 0 )
{
init_hexbytes_noT(hexstr,(uint8_t *)msg,msg->sig.allocsize);
if ( (retstr= SuperNET_categorymulticast(myinfo,0,myinfo->instantdex_category,desthash,hexstr,0,hops,1,argjson,0)) != 0 )
free(retstr);
free(hexstr);
}
9 years ago
}
9 years ago
free(msg);
9 years ago
return(jprint(argjson,1));
9 years ago
}
else
{
9 years ago
free_json(argjson), free(msg);
9 years ago
printf("cant msgcreate datalen.%d\n",datalen);
9 years ago
return(clonestr("{\"error\":\"couldnt create instantdex message\"}"));
}
}
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
int32_t instantdex_updatesources(struct exchange_info *exchange,struct exchange_quote *sortbuf,int32_t n,int32_t max,int32_t ind,int32_t dir,struct exchange_quote *quotes,int32_t numquotes)
9 years ago
{
int32_t i; struct exchange_quote *quote;
9 years ago
//printf("instantdex_updatesources update dir.%d numquotes.%d\n",dir,numquotes);
9 years ago
for (i=0; i<numquotes; i++)
{
quote = &quotes[i << 1];
9 years ago
//printf("n.%d ind.%d i.%d dir.%d price %.8f vol %.8f\n",n,ind,i,dir,quote->price,quote->volume);
if ( quote->price > SMALLVAL )
{
9 years ago
sortbuf[n] = *quote;
sortbuf[n].val = ind;
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
sortbuf[n].exchangebits = exchange->exchangebits;
9 years ago
//printf("sortbuf[%d] <-\n",n*2);
9 years ago
if ( ++n >= max )
break;
9 years ago
}
9 years ago
}
9 years ago
return(n);
9 years ago
}
9 years ago
double instantdex_aveprice(struct supernet_info *myinfo,struct exchange_quote *sortbuf,int32_t max,double *totalvolp,char *base,char *rel,double basevolume,cJSON *argjson)
9 years ago
{
9 years ago
char *str; double totalvol,pricesum; uint32_t timestamp;
9 years ago
struct exchange_quote quote; int32_t i,n,dir,num,depth = 100;
9 years ago
struct exchange_info *exchange; struct exchange_request *req,*active[64];
9 years ago
timestamp = (uint32_t)time(NULL);
9 years ago
if ( basevolume < 0. )
basevolume = -basevolume, dir = -1;
9 years ago
else dir = 1;
memset(sortbuf,0,sizeof(*sortbuf) * max);
9 years ago
if ( base != 0 && rel != 0 && basevolume > SMALLVAL )
9 years ago
{
9 years ago
for (i=num=0; i<myinfo->numexchanges && num < sizeof(active)/sizeof(*active); i++)
{
9 years ago
if ( (exchange= myinfo->tradingexchanges[i]) != 0 )
{
9 years ago
if ( (req= exchanges777_baserelfind(exchange,base,rel,'M')) == 0 )
{
if ( (str= exchanges777_Qprices(exchange,base,rel,30,1,depth,argjson,1,exchange->commission)) != 0 )
free(str);
req = exchanges777_baserelfind(exchange,base,rel,'M');
}
if ( req == 0 )
{
if ( (*exchange->issue.supports)(exchange,base,rel,argjson) != 0 )
printf("unexpected null req.(%s %s) %s\n",base,rel,exchange->name);
}
else
{
9 years ago
//printf("active.%s\n",exchange->name);
9 years ago
active[num++] = req;
}
}
9 years ago
}
for (i=n=0; i<num; i++)
{
9 years ago
if ( dir < 0 && active[i]->numbids > 0 )
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
n = instantdex_updatesources(active[i]->exchange,sortbuf,n,max,i,1,active[i]->bidasks,active[i]->numbids);
9 years ago
else if ( dir > 0 && active[i]->numasks > 0 )
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
n = instantdex_updatesources(active[i]->exchange,sortbuf,n,max,i,-1,&active[i]->bidasks[1],active[i]->numasks);
}
9 years ago
//printf("dir.%d %s/%s numX.%d n.%d\n",dir,base,rel,num,n);
if ( dir < 0 )
revsort64s(&sortbuf[0].satoshis,n,sizeof(*sortbuf));
else sort64s(&sortbuf[0].satoshis,n,sizeof(*sortbuf));
9 years ago
for (totalvol=pricesum=i=0; i<n && totalvol < basevolume; i++)
9 years ago
{
9 years ago
quote = sortbuf[i];
//printf("n.%d i.%d price %.8f %.8f %.8f\n",n,i,dstr(sortbuf[i].satoshis),sortbuf[i].price,quote.volume);
if ( quote.satoshis != 0 )
9 years ago
{
9 years ago
pricesum += (quote.price * quote.volume);
totalvol += quote.volume;
9 years ago
printf("i.%d of %d %12.8f vol %.8f %s | aveprice %.8f total vol %.8f\n",i,n,sortbuf[i].price,quote.volume,active[quote.val]->exchange->name,pricesum/totalvol,totalvol);
9 years ago
}
}
if ( totalvol > 0. )
9 years ago
{
many changes blockexplorer tab: needs to allow to input height, blockhash or txid. also please display images/BTC_blocks.jpg below the text as a w800 x h400 bitmap, which is active using the mouse api for coin management, below the active coins have a form that arbitrary json can be input with an add button to the right that will call &#34;addcoin&#34; API. this way I can test adding new coins dynamically. dont worry if it doesnt work, just as long as it submits the json to the C code. I am pretty sure I need to do some debugging of this peers management is not working for me at all. maybe it is due to bad internet. On initialization you need to read in the confs/BTCD_peers.txt from the native filesystem and save it into the chrome app filesystem. same thing for confs/BTCD_hdrs.txt. But this is only to be done if there isnt already such a file inside chrome. if there is, only do it upon a button invoked by the user. the reason is that the pexe is updating this file with the latest. Maybe it is nice to have an &#34;extract&#34; button that will copy out from the chrome storage into the native filesystem. There is also the manifest issue about localstorage vs chrome.localstorage. not sure what is needed to be done, but certainly a priority to get it so everything works as a chrome app. I know before it was making ramchain files inside the chrome filesystem, so it is probably things the GUI is doing. maybe in the settings tab, which has obsolete stuff that can be removed. anyway, the issue about files existing in the native filesystem -&gt; chrome and optionally extracting them is an issue for the confs files and .html template files used to autogenerate the port7778, maybe other files are affected. i think we need a way to have a list of hardcoded files that are just copied into chrome on startup if they dont exist already (or if possible copy over if the native version is bigger?) and buttons to extract them for debug tab: THREE_STRINGS(SuperNET,encryptjson,passphrase,permanentfile,anything); TWO_STRINGS(SuperNET,decryptjson,passphrase,permanentfile); at the top of page a way to put in passphrase and optional permanentfile along with arbitrary json. The standard form template has no easy way to describe to pass in everything as it is oriented to specific fields. but the encryptjson API saves all the fields, so the arbitrary json from the form needs to be combined at the same level as the &#34;agent&#34;, &#34;method&#34;, etc. I know, not the best, but internally it makes it easier. so {&#34;agent&#34;:&#34;SuperNET&#34;,&#34;method&#34;:&#34;encryptjson&#34;,&#34;passphrase&#34;:&#34;&lt;passphrase&gt;&#34;,&#34; permanentfile&#34;:&#34;&lt;filename&gt;&#34;,&#34;fromform&#34;:&#34;valuefromform&#34;,&#34;fromform2&#34;:&#34;valu efromform2&#34;,...rest of form at top level} then this will save it into a file with crazy number (it is a hash like txid) but given the same passphrase and filename, it will regenerate this hash so you dont actually have to store it, but it helps during debugging. for the filename, we must warn quite strongly to the user that if the file is ever lost or even changed in any way that the data will not be recoverable. also best to not allow the user to specify a file that does not exist. I think at this point chrome app version gets a bit tricky. we could simply push the native file into the chrome storage, but then an attacker who gets access to the computer could just get a list of these files and it really wont be much protection. So that means if a filename is specified, it needs to be copied into the chrome space, then immediately deleted... ok, this seems like not a good approach. let us make it so that the permanentfile option is not available from the chrome app, but only if the native version is running. that way we sidestep the issue of the pexe not having access to the specified file. Speaking of native vs pexe, on the startup page we should have a radio button that allows the user to select which the GUI will talk to. It should default based on a self test to the more likely value, but it is possible that the user wants to use the native version, even if the pexe is running. another thing to have on the startup page is a simple login: THREE_STRINGS(SuperNET,login,passphrase,permanentfile,handle); ZERO_ARGS(SuperNET,logout); ZERO_ARGS(SuperNET,activehandle); the handle is a human readable name that is associated with the passphrase/permanentfile. There can only be one active account (though it will be possible to associate different accounts with tradebots). use the activehandle API to find out who is logged in and the associated addresses and pubkeys The above is not yet tested so if it doesnt work, dont fret, just let me know. Once set the handle can be displayed in various places to let the user know which account is logged in. The standard 12 dictionary word passphrases should be used, but any string can be sent in as the password for Pangea: INT_AND_ARRAY(pangea,host,minplayers,params); ZERO_ARGS(pangea,lobby); HASH_AND_STRING(pangea,join,tablehash,handle); HASH_AND_INT(pangea,buyin,tablehash,numchips); HASH_ARG(pangea,start,tablehash); // by host only HASH_ARG(pangea,status,tablehash); HASH_ARG(pangea,call,tablehash); HASH_ARG(pangea,check,tablehash); HASH_AND_INT(pangea,raise,tablehash,numchips); HASH_AND_INT(pangea,bet,tablehash,numchips); HASH_ARG(pangea,fold,tablehash); HASH_AND_STRING(pangea,mode,tablehash,modestr); HASH_ARG(pangea,history,tablehash); HASH_AND_INT(pangea,handhistory,tablehash,hand); The first thing that is done is a &#34;host&#34; by any node. the &#34;params&#34; should be an arbitrary json (like encryptjson) as it needs to be at the top level and it has quite a few different parameters still subject to change. The lobby API will just display all the hosted tables. once a table exists, players can join and then buyin. the buyin is denominated in chips, each chip&#39;s value is determined by the host&#39;s initial parameters. once there are enough players joined with adequate buyin&#39;s verified, the host will be able to do a start. if done before it will (eventually) give an error. for now it will just proceed. The host and players that have joined a tablehash, need to do regular status calls to see if the game has started. Probably just once per 5 or even 10 seconds is fine before the start. Once the game starts (the status will have this info) then once per second polling is needed. Then when it is your turn (as indicated by status) you need to do one of the 5 actions (fold, call, check, raise, bet). do not worry if you dont understand what all these do, just allow the user to do any of these. I guess it is possible to submit it ahead of time. I will support internally remembering the most recent action done prior to it being your turn. once it is your turn and an action is sent to the table, it is too late to change. The last API calls are for getting handhistory where hand is 0 to N-1, being the numbering of the hands played at that table. if just history, all the history for all hands at the table is coming back, so it could be quite big. probably I will make it a summary, but for the GUI just display the returned values. the mode is to change some poker specific modes, so just allow there to be a string entered. do not worry about understanding the pokerness of the API, just the overall flow: host -&gt; creates, join/buyin -&gt; fills up player slots, start -&gt; starts the game status -&gt; to determine when the game starts (or if it is cancelled) and once started actions -&gt; game specific but basically just (button + arg) that is the user input results are via status for current game and history for past ones please try to do the above logic in a generic way so it can be reused for other games. The basic flow should be the same for almost all multiplayer turn based games and even for multiplayer realtime games For InstantDEX: on the apikeypair/userid there needs to be two modes. one for when there is no stored apikey and the current form is fine, just need to make it wider as most apikeys are quite long. Now once there is an apikey saved all that is needed is the passphrase to unlock it. So here is where the encrptjson/decryptjson is used. When saving the apikey for the first time, it can be: a) not saved -&gt; nothing extra to do b) saved without password -&gt; you can just save to a file and use it to load it back in. use confs dir confs/instantdex.exchange.api or something like that c) saved with password (optional filename for native) -&gt; probably best to save in the confs dir to indicate that there is an encrypted file for this, so just that and not the actual passphrase in the file with the above, when the exchange is selected, you can see if the confs file exists and if it has the plaintext, just populate the field, if not, then indicate that a passphrase is needed. if the user provides the passphrase, then decryptjson and populate the fields and autosubmit. A special case is to encrypt the apikeys with the passphrase used when logging in. This is only available if the checkbox to &#34;remember passphrase during session&#34; is set on the main iguana login screen. (i forgot to mention that checkbox!) So the login passphrase is stored in memory, then the GUI simply uses that + encryptjson for storing/decrypting. I would imagine that storing in the confs file that it is encrypted using &#34;handle&#34;&#39;s account login might be a good way to differentiate between this mode of password usage. OK, so we now have the insecure plaintext, the decent using handle&#39;s passphrase and paranoid different passphrase for each exchange (with additional permanentfile for native versions) &#34;SUPPORT&#34; -&gt; &#34;SUPPORTS&#34; just a typo and &#34;allpairs&#34; API is missing from the selection Might as well add a &#34;tradebots&#34; tab: THREE_STRINGS_AND_DOUBLE(tradebot,monitor,exchange,base,rel,commission); STRING_AND_DOUBLE(tradebot,monitorall,exchange,commission); THREE_STRINGS(tradebot,unmonitor,exchange,base,rel); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,accumulate,exchange,base,rel,pr ice,volume,duration); THREE_STRINGS_AND_THREE_DOUBLES(tradebot,divest,exchange,base,rel,price, volume,duration); STRING_ARG(tradebot,activebots,exchange); TWO_STRINGS(tradebot,status,exchange,botid); TWO_STRINGS(tradebot,pause,exchange,botid); TWO_STRINGS(tradebot,stop,exchange,botid); TWO_STRINGS(tradebot,resume,exchange,botid); the above are API for exchange specific bots, most should be self-explanatory. bots are created via &#34;accumulate&#34; or &#34;divest&#34; API call. it returns botid. once created, you can do status, pause, stop, resume to a botid. and an activebots API call lists all the active bots for an exchange. duration is in seconds the &#34;monitor&#34; API starts background monitoring of a specific base/rel, &#34;unmonitor&#34; stops this. &#34;monitorall&#34; just does a monitor to the entire list of &#34;allpairs&#34; for that exchange. Keep in mind that doing a monitorall will not add load to an exchange as the request to each exchange is governed by pollgap, but if you have 3 things monitored, it will take 3*pollgap + time each one takes to execute. and if N are monitored it is N*pollgap + time of each, with the &#34;time of each&#34; possibly taking a very long time. And one final request for today: Bitmap tab. It should be an active bitmap using mouse api. either a dropdown to select the bitmap or a form entry. then the rest of the page (resize the bitmap to the page size) being the active bitmap. So on a small screen the bitmap is smaller x/y dimensions and larger on larger screens. plz make sure the proper dimensions are communicated to the pexe via API if it ever is changed. @vineet.bhargav86: I changed the &#34;passphrase&#34; fieldname to &#34;password&#34; for the encryptjson/decryptjson related API. The reason is that the password is like a wallet password and is only local, so it doesnt need to be as high entropy as passphrase. I also added a field to the login API as I realized that the 12 word &#34;passphrase&#34; is the payload and usually wont be sent in: FOUR_STRINGS(SuperNET,login,handle,password,permanentfile,passphrase); using &#34;abiglongpassword&#34; for the passphrase -&gt; {&#34;pubkey&#34;:&#34;6c469ba10b40b3eb9d1dba569d7f929d55a29d8f97cd5425907ef2f38f906 209&#34;,&#34;RS&#34;:&#34;NXT-KGV9-DXX8-TM86-DXR96&#34;,&#34;NXT&#34;:&#34;12834974574569896807&#34;,&#34;btcpu bkey&#34;:&#34;024e7641dc947b211bc30fe3339765258902794687b227121fc217284f9d8503c 8&#34;,&#34;rmd160&#34;:&#34;33453c24914db7b77069b7ea24df44f6be145938&#34;,&#34;BTC&#34;:&#34;15g6QK2dSd iW9ZTQEnnJxKrSph6uP7uU23&#34;,&#34;BTCD&#34;:&#34;RDxHUpuv3TX5DZpbhxmS3rBeaxZW1fvYvC&#34;,&#34;r esult&#34;:&#34;success&#34;,&#34;handle&#34;:&#34;test&#34;,&#34;tag&#34;:&#34;14805226009240621255&#34;} and if you use that to log into NXT, it gives the same address. The BTC and BTCD addresses are all derived from the same privkey so they are all interchangeable with the NXT address. The user can therefore select which coin&#39;s addressing they are most comfortable with I also added an &#34;allin&#34; action API for pangea. all the action API will autocalculate the number of chips if passed in 0 for numchips ***************** security issue ******** please dont use the GET URL method when dealing with passphrase!!! Those URL&#39;s tend to get logged and available in browser histories. so anything dealing with the actual passphrase needs to use the postCall form or POST
9 years ago
*totalvolp = totalvol;
9 years ago
return(pricesum / totalvol);
9 years ago
}
9 years ago
}
9 years ago
*totalvolp = 0;
9 years ago
return(0);
}
9 years ago
double instantdex_avehbla(struct supernet_info *myinfo,double retvals[4],char *base,char *rel,double basevolume)
{
double avebid,aveask,bidvol,askvol; struct exchange_quote sortbuf[256]; cJSON *argjson;
argjson = cJSON_CreateObject();
aveask = instantdex_aveprice(myinfo,sortbuf,sizeof(sortbuf)/sizeof(*sortbuf),&askvol,base,rel,basevolume,argjson);
avebid = instantdex_aveprice(myinfo,sortbuf,sizeof(sortbuf)/sizeof(*sortbuf),&bidvol,base,rel,-basevolume,argjson);
free_json(argjson);
retvals[0] = avebid, retvals[1] = bidvol, retvals[2] = aveask, retvals[3] = askvol;
if ( avebid > SMALLVAL && aveask > SMALLVAL )
return((avebid + aveask) * .5);
else return(0);
}
int32_t instantdex_bidaskdir(struct instantdex_offer *offer)
9 years ago
{
if ( offer->myside == 0 && offer->acceptdir > 0 ) // base
9 years ago
return(-1);
else if ( offer->myside == 1 && offer->acceptdir < 0 ) // rel
9 years ago
return(1);
9 years ago
else return(0);
}
9 years ago
cJSON *instantdex_offerjson(struct instantdex_offer *offer,uint64_t orderid)
9 years ago
{
int32_t dir; cJSON *item = cJSON_CreateObject();
9 years ago
jadd64bits(item,"orderid",orderid);
9 years ago
jadd64bits(item,"account",offer->account);
if ( (dir= instantdex_bidaskdir(offer)) > 0 )
9 years ago
jaddstr(item,"type","bid");
else if ( dir < 0 )
jaddstr(item,"type","ask");
else
{
jaddstr(item,"type","strange");
jaddnum(item,"acceptdir",offer->acceptdir);
jaddnum(item,"myside",offer->myside);
}
jaddstr(item,"base",offer->base);
jaddstr(item,"rel",offer->rel);
jaddnum(item,"timestamp",offer->expiration);
jaddnum(item,"price",dstr(offer->price64));
jaddnum(item,"volume",dstr(offer->basevolume64));
9 years ago
jaddnum(item,"minperc",offer->minperc);
jaddnum(item,"nonce",offer->nonce);
jaddnum(item,"expiresin",offer->expiration - time(NULL));
return(item);
}
cJSON *instantdex_acceptjson(struct instantdex_accept *ap)
{
cJSON *item = cJSON_CreateObject();
jadd64bits(item,"orderid",ap->orderid);
9 years ago
jaddnum(item,"pendingvolume",dstr(ap->pendingvolume64));
if ( ap->dead != 0 )
jadd64bits(item,"dead",ap->dead);
9 years ago
jadd(item,"offer",instantdex_offerjson(&ap->offer,ap->orderid));
9 years ago
return(item);
}
void instantdex_statetxjson(cJSON *array,char *name,struct bitcoin_statetx *tx)
{
cJSON *item;
if ( tx != 0 )
{
9 years ago
item = cJSON_CreateObject();
jaddbits256(item,"txid",tx->txid);
jaddnum(item,"inputsum",dstr(tx->inputsum));
jaddnum(item,"amount",dstr(tx->amount));
jaddnum(item,"change",dstr(tx->change));
jaddnum(item,"txfee",dstr(tx->inputsum) - dstr(tx->amount) - dstr(tx->change));
jaddnum(item,"confirms",dstr(tx->numconfirms));
jaddstr(item,"destaddr",tx->destaddr);
jaddstr(item,"txbytes",tx->txbytes);
jadd(array,name,item);
}
9 years ago
}
9 years ago
cJSON *instantdex_statemachinejson(struct bitcoin_swapinfo *swap)
{
9 years ago
cJSON *retjson,*txs; int32_t isbob,mydir,otherdir;
retjson = cJSON_CreateObject();
if ( swap != 0 )
{
9 years ago
mydir = instantdex_bidaskdir(&swap->mine.offer);
otherdir = instantdex_bidaskdir(&swap->other.offer);
isbob = instantdex_isbob(swap);
jaddnum(retjson,"isbob",isbob);
jaddnum(retjson,"mydir",mydir);
jaddnum(retjson,"otherdir",otherdir);
jaddnum(retjson,"expiration",swap->expiration);
jaddnum(retjson,"insurance",dstr(swap->insurance));
jaddnum(retjson,"baseamount",dstr(swap->altsatoshis));
jaddnum(retjson,"BTCamount",dstr(swap->BTCsatoshis));
jaddnum(retjson,"expiration",swap->expiration);
if ( swap->dead != 0 )
jadd64bits(retjson,"dead",swap->dead);
jaddbits256(retjson,"privAm",swap->privAm);
jaddbits256(retjson,"pubAm",swap->pubAm);
jaddbits256(retjson,"privBn",swap->privBn);
jaddbits256(retjson,"pubBn",swap->pubBn);
9 years ago
9 years ago
jaddbits256(retjson,"myorderhash",swap->myorderhash);
jaddnum(retjson,"choosei",swap->choosei);
jaddnum(retjson,"cutverified",swap->cutverified);
jaddbits256(retjson,"othertrader",swap->othertrader);
9 years ago
jaddbits256(retjson,"otherorderhash",swap->otherorderhash);
jaddnum(retjson,"otherchoosei",swap->otherchoosei);
jaddnum(retjson,"otherverifiedcut",swap->otherverifiedcut);
if ( isbob == 0 )
{
jaddbits256(retjson,"pubA0",swap->mypubs[0]);
jaddbits256(retjson,"pubA1",swap->mypubs[1]);
jaddbits256(retjson,"pubB0",swap->otherpubs[0]);
jaddbits256(retjson,"pubB1",swap->otherpubs[1]);
}
else
{
jaddbits256(retjson,"pubB0",swap->mypubs[0]);
jaddbits256(retjson,"pubB1",swap->mypubs[1]);
jaddbits256(retjson,"pubA0",swap->otherpubs[0]);
jaddbits256(retjson,"pubA1",swap->otherpubs[1]);
}
9 years ago
if ( mydir > 0 && otherdir < 0 )
{
jadd64bits(retjson,"bidid",swap->mine.orderid);
jadd64bits(retjson,"askid",swap->other.orderid);
}
else if ( mydir < 0 && otherdir > 0 )
{
jadd64bits(retjson,"askid",swap->mine.orderid);
jadd64bits(retjson,"bidid",swap->other.orderid);
}
if ( swap->matched64 == swap->mine.orderid )
{
jadd(retjson,"initiator",instantdex_acceptjson(&swap->other));
jadd(retjson,"matched",instantdex_acceptjson(&swap->mine));
}
else if ( swap->matched64 == swap->other.orderid )
{
jadd(retjson,"initiator",instantdex_acceptjson(&swap->mine));
jadd(retjson,"matched",instantdex_acceptjson(&swap->other));
}
else jaddstr(retjson,"initiator","illegal initiator missing");
if ( swap->state != 0 )
jaddstr(retjson,"state",swap->state->name);
txs = cJSON_CreateObject();
9 years ago
instantdex_statetxjson(txs,"deposit",swap->deposit);
instantdex_statetxjson(txs,"payment",swap->payment);
instantdex_statetxjson(txs,"altpayment",swap->altpayment);
instantdex_statetxjson(txs,"myfee",swap->myfee);
instantdex_statetxjson(txs,"otherfee",swap->otherfee);
jadd(retjson,"txs",txs);
jaddstr(retjson,"status",swap->status);
}
return(retjson);
}
9 years ago
cJSON *instantdex_historyjson(struct bitcoin_swapinfo *swap)
{
// need to make sure accepts are put onto history queue when they are completed or deaded
// also to make permanent copy (somewhere)
9 years ago
return(instantdex_statemachinejson(swap));
}
9 years ago
void instantdex_historyadd(struct exchange_info *exchange,struct bitcoin_swapinfo *swap)
{
portable_mutex_lock(&exchange->mutexH);
DL_APPEND(exchange->history,swap);
portable_mutex_unlock(&exchange->mutexH);
}
void instantdex_statemachineadd(struct exchange_info *exchange,struct bitcoin_swapinfo *swap)
{
portable_mutex_lock(&exchange->mutexS);
DL_APPEND(exchange->statemachines,swap);
portable_mutex_unlock(&exchange->mutexS);
}
void instantdex_offeradd(struct exchange_info *exchange,struct instantdex_accept *ap)
9 years ago
{
9 years ago
portable_mutex_lock(&exchange->mutex);
9 years ago
DL_APPEND(exchange->offers,ap);
portable_mutex_unlock(&exchange->mutex);
}
9 years ago
struct bitcoin_swapinfo *instantdex_historyfind(struct supernet_info *myinfo,struct exchange_info *exchange,uint64_t orderid)
{
struct bitcoin_swapinfo *swap,*tmp,*retswap = 0;
portable_mutex_lock(&exchange->mutexH);
DL_FOREACH_SAFE(exchange->history,swap,tmp)
{
if ( orderid == swap->mine.orderid )
{
retswap = swap;
break;
}
}
portable_mutex_unlock(&exchange->mutexH);
return(retswap);
}
9 years ago
struct bitcoin_swapinfo *instantdex_statemachinefind(struct supernet_info *myinfo,struct exchange_info *exchange,uint64_t orderid)
{
struct bitcoin_swapinfo *tmp,*swap,*retswap = 0; uint32_t now;
now = (uint32_t)time(NULL);
portable_mutex_lock(&exchange->mutexS);
DL_FOREACH_SAFE(exchange->statemachines,swap,tmp)
9 years ago
{
9 years ago
if ( now < swap->expiration && swap->mine.dead == 0 && swap->other.dead == 0 )
9 years ago
{
9 years ago
if ( orderid == swap->mine.orderid || orderid == swap->other.orderid )
9 years ago
{
9 years ago
retswap = swap;
9 years ago
break;
9 years ago
}
9 years ago
}
else
{
9 years ago
strcpy(swap->status,"expired");
9 years ago
printf("expired pending, need to take action, send timeout event\n");
9 years ago
DL_DELETE(exchange->statemachines,swap);
instantdex_historyadd(exchange,swap);
9 years ago
continue;
9 years ago
}
}
9 years ago
//printf("found statemachine.%p\n",retswap);
9 years ago
portable_mutex_unlock(&exchange->mutexS);
9 years ago
return(retswap);
9 years ago
}
9 years ago
struct instantdex_accept *instantdex_offerfind(struct supernet_info *ignore,struct exchange_info *exchange,cJSON *bids,cJSON *asks,uint64_t orderid,char *base,char *rel,int32_t report)
9 years ago
{
9 years ago
struct instantdex_accept *tmp,*ap,*retap = 0; uint32_t now; cJSON *item,*offerobj; char *type;
if ( exchange == 0 )
return(0);
9 years ago
now = (uint32_t)time(NULL);
9 years ago
portable_mutex_lock(&exchange->mutex);
DL_FOREACH_SAFE(exchange->offers,ap,tmp)
9 years ago
{
9 years ago
if ( now < ap->offer.expiration && ap->dead == 0 )
9 years ago
{
9 years ago
//printf("%d %d find cmps %d %d %d %d %d %d me.%llu vs %llu o.%llu | vs %llu\n",instantdex_bidaskdir(&ap->offer),ap->offer.expiration-now,strcmp(base,"*") == 0,strcmp(base,ap->offer.base) == 0,strcmp(rel,"*") == 0,strcmp(rel,ap->offer.rel) == 0,orderid == 0,orderid == ap->orderid,(long long)myinfo->myaddr.nxt64bits,(long long)ap->offer.account,(long long)ap->orderid,(long long)orderid);
9 years ago
if ( (report == 0 || ap->reported == 0) && (strcmp(base,"*") == 0 || strcmp(base,ap->offer.base) == 0) && (strcmp(rel,"*") == 0 || strcmp(rel,ap->offer.rel) == 0) && (orderid == 0 || orderid == ap->orderid) )
9 years ago
{
9 years ago
if ( report != 0 && ap->reported == 0 )
{
9 years ago
ap->reported = 1;
9 years ago
printf("MARK as reported %llu\n",(long long)ap->orderid);
}
9 years ago
retap = ap;
9 years ago
if ( (item= instantdex_acceptjson(ap)) != 0 )
{
//printf("item.(%s)\n",jprint(item,0));
if ( (offerobj= jobj(item,"offer")) != 0 && (type= jstr(offerobj,"type")) != 0 )
{
if ( bids != 0 && strcmp(type,"bid") == 0 )
jaddi(bids,jduplicate(offerobj));
else if ( asks != 0 && strcmp(type,"ask") == 0 )
jaddi(asks,jduplicate(offerobj));
}
free_json(item);
} else printf("error generating acceptjson.%llu\n",(long long)ap->orderid);
9 years ago
}
9 years ago
}
else
{
DL_DELETE(exchange->offers,ap);
free(ap);
}
9 years ago
}
9 years ago
portable_mutex_unlock(&exchange->mutex);
9 years ago
//printf("offerfind -> retap.%p Qsize.%d\n",retap,queue_size(&exchange->acceptableQ));
9 years ago
return(retap);
}
9 years ago
int32_t instantdex_peerhas_clear(struct iguana_info *coin,struct iguana_peer *addr)
{
9 years ago
struct instantdex_accept *tmp,*ap; struct exchange_info *exchange; int32_t ind,num = 0;
if ( addr != 0 && (exchange= exchanges777_find("bitcoin")) != 0 )
{
9 years ago
//printf("clear all bits for addrind.%d\n",addr->addrind);
ind = addr->addrind;
9 years ago
portable_mutex_lock(&exchange->mutex);
DL_FOREACH_SAFE(exchange->offers,ap,tmp)
{
CLEARBIT(ap->peerhas,ind);
}
9 years ago
portable_mutex_unlock(&exchange->mutex);
}
return(num);
}
9 years ago
struct instantdex_accept *instantdex_acceptable(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *A,double minperc)
{
9 years ago
struct instantdex_accept *tmp,*ap,*retap = 0; double aveprice;
uint64_t minvol,bestprice64 = 0; uint32_t now; int32_t offerdir;
if ( exchange == 0 )
{
9 years ago
printf("instantdex_acceptable null exchange\n");
return(0);
}
9 years ago
aveprice = 0;//instantdex_avehbla(myinfo,retvals,A->offer.base,A->offer.rel,dstr(A->offer.basevolume64));
now = (uint32_t)time(NULL);
offerdir = instantdex_bidaskdir(&A->offer);
minvol = (A->offer.basevolume64 * minperc * .01);
printf("instantdex_acceptable offerdir.%d (%s/%s) minperc %.3f minvol %.8f vs %.8f\n",offerdir,A->offer.base,A->offer.rel,minperc,dstr(minvol),dstr(A->offer.basevolume64));
portable_mutex_lock(&exchange->mutex);
DL_FOREACH_SAFE(exchange->offers,ap,tmp)
9 years ago
{
9 years ago
//printf("ap.%p account.%llu dir.%d\n",ap,(long long)ap->offer.account,offerdir);
9 years ago
if ( now > ap->offer.expiration || ap->dead != 0 || A->offer.account == ap->offer.account )
9 years ago
{
//printf("now.%u skip expired %u/dead.%u or my order orderid.%llu from %llu\n",now,ap->offer.expiration,ap->dead,(long long)ap->orderid,(long long)ap->offer.account);
}
else if ( A->offer.account != myinfo->myaddr.nxt64bits && ap->offer.account != myinfo->myaddr.nxt64bits )
{
}
else if ( strcmp(ap->offer.base,A->offer.base) != 0 || strcmp(ap->offer.rel,A->offer.rel) != 0 )
{
//printf("skip mismatched.(%s/%s) orderid.%llu from %llu\n",ap->offer.base,ap->offer.rel,(long long)ap->orderid,(long long)ap->offer.account);
}
else if ( offerdir*instantdex_bidaskdir(&ap->offer) > 0 )
{
//printf("skip same direction %d orderid.%llu from %llu\n",instantdex_bidaskdir(&ap->offer),(long long)ap->orderid,(long long)ap->offer.account);
}
else if ( minvol > ap->offer.basevolume64 - ap->pendingvolume64 )
{
//printf("skip too small order %.8f vs %.8f orderid.%llu from %llu\n",dstr(minvol),dstr(ap->offer.basevolume64)-dstr(ap->pendingvolume64),(long long)ap->orderid,(long long)ap->offer.account);
}
else if ( (offerdir > 0 && ap->offer.price64 > A->offer.price64) || (offerdir < 0 && ap->offer.price64 < A->offer.price64) )
{
//printf("skip out of band dir.%d offer %.8f vs %.8f orderid.%llu from %llu\n",offerdir,dstr(ap->offer.price64),dstr(A->offer.price64),(long long)ap->orderid,(long long)ap->offer.account);
}
else
{
if ( bestprice64 == 0 || (offerdir > 0 && ap->offer.price64 < bestprice64) || (offerdir < 0 && ap->offer.price64 > bestprice64) )
{
printf(">>>> MATCHED better price dir.%d offer %.8f vs %.8f orderid.%llu from %llu\n",offerdir,dstr(ap->offer.price64),dstr(A->offer.price64),(long long)ap->orderid,(long long)ap->offer.account);
bestprice64 = ap->offer.price64;
retap = ap;
}
}
9 years ago
}
9 years ago
portable_mutex_unlock(&exchange->mutex);
//printf("after acceptable Qsize.%d retap.%p\n",queue_size(&exchange->acceptableQ),retap);
return(retap);
}
9 years ago
int32_t instantdex_inv2data(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,struct exchange_info *exchange)
{
9 years ago
struct instantdex_accept *tmp,*ap; uint32_t now,n=0,len; bits256 encodedhash,hashes[100]; uint8_t serialized[100*36 + 1024];
9 years ago
//printf("instantdex_inv2data exchange.%p (%s)\n",exchange,addr->ipaddr);
9 years ago
if ( exchange == 0 )
return(0);
9 years ago
portable_mutex_lock(&exchange->mutex);
9 years ago
now = (uint32_t)time(NULL);
9 years ago
DL_FOREACH_SAFE(exchange->offers,ap,tmp)
9 years ago
{
if ( now < ap->offer.expiration && ap->dead == 0 )
{
9 years ago
encodedhash = instantdex_encodehash(ap->offer.base,ap->offer.rel,ap->offer.price64*instantdex_bidaskdir(&ap->offer),ap->orderid,ap->offer.account);
9 years ago
if ( n < sizeof(hashes)/sizeof(*hashes) )//&& GETBIT(ap->peerhas,addr->addrind) == 0 )
9 years ago
{
9 years ago
hashes[n++] = encodedhash;
9 years ago
printf("%llu ",(long long)ap->orderid);
}
9 years ago
}
else
{
DL_DELETE(exchange->offers,ap);
free(ap);
}
9 years ago
}
9 years ago
portable_mutex_unlock(&exchange->mutex);
9 years ago
if ( n > 0 )
{
len = iguana_inv2packet(serialized,sizeof(serialized),MSG_QUOTE,hashes,n);
9 years ago
//printf("Send inv2[%d] -> (%s)\n",n,addr->ipaddr);
9 years ago
return(iguana_queue_send(coin,addr,0,serialized,"inv2",len,0,0));
}
return(-1);
}
struct instantdex_accept *instantdex_quotefind(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,bits256 encodedhash)
{
9 years ago
char base[9],rel[9]; int64_t pricetoshis; uint64_t orderid,account;
orderid = instantdex_decodehash(base,rel,&pricetoshis,&account,encodedhash);
//printf("search for orderid.%llu (%s/%s) %.8f from %llu\n",(long long)orderid,base,rel,dstr(pricetoshis),(long long)account);
9 years ago
return(instantdex_offerfind(myinfo,exchanges777_find("bitcoin"),0,0,orderid,base,rel,0));
}
9 years ago
struct iguana_bundlereq *instantdex_recvquotes(struct iguana_info *coin,struct iguana_bundlereq *req,bits256 *quotes,int32_t n)
9 years ago
{
9 years ago
int32_t i,len,m = 0; uint8_t serialized[10000];
9 years ago
if ( req->addr == 0 )
return(0);
9 years ago
//printf("received quotehashes.%d from (%s)\n",n,req->addr->ipaddr);
9 years ago
for (i=1; i<n; i++)
9 years ago
{
9 years ago
if ( instantdex_quotefind(0,coin,req->addr,quotes[i]) != 0 )
continue;
quotes[m++] = quotes[i];
}
if ( m > 0 )
{
len = iguana_getdata(coin,serialized,MSG_QUOTE,quotes,m);
9 years ago
printf("send getdata for %d of %d quotes to %s\n",m,n,req->addr->ipaddr);
iguana_send(coin,req->addr,serialized,len);
9 years ago
}
9 years ago
return(req);
9 years ago
}
int32_t instantdex_quoterequest(struct supernet_info *myinfo,struct iguana_info *coin,uint8_t *serialized,int32_t maxlen,struct iguana_peer *addr,bits256 encodedhash)
{
9 years ago
struct instantdex_accept *ap; int32_t olen,checklen; struct instantdex_offer checkoffer; bits256 orderhash,checkhash;
if ( (ap= instantdex_quotefind(myinfo,coin,addr,encodedhash)) != 0 )
{
orderhash = instantdex_rwoffer(1,&olen,serialized,&ap->offer);
if ( orderhash.ulongs[0] == ap->orderid )
9 years ago
{
checkhash = instantdex_rwoffer(0,&checklen,serialized,&checkoffer);
9 years ago
if ( bits256_cmp(checkhash,orderhash) != 0 )
printf("%llu vs %llu, %d vs %d\n",(long long)checkhash.txid,(long long)orderhash.txid,checklen,olen);
return(olen);
9 years ago
}
else return(-1);
}
return(0);
}
9 years ago
int32_t instantdex_quotep2p(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,uint8_t *serialized,int32_t recvlen)
{
9 years ago
bits256 orderhash,encodedhash; int32_t added,checklen; struct instantdex_accept A,*ap; struct exchange_info *exchange; char *retstr; cJSON *argjson; uint64_t txid;
9 years ago
exchange = exchanges777_find("bitcoin");
memset(&A,0,sizeof(A));
9 years ago
orderhash = instantdex_rwoffer(0,&checklen,serialized,&A.offer), A.orderid = orderhash.txid;
if ( checklen == recvlen )
{
9 years ago
encodedhash = instantdex_encodehash(A.offer.base,A.offer.rel,A.offer.price64 * instantdex_bidaskdir(&A.offer),A.orderid,A.offer.account);
9 years ago
//printf("before quotefind.%d\n",queue_size(&exchange->acceptableQ));
if ( (ap= instantdex_quotefind(myinfo,coin,addr,encodedhash)) == 0 )
{
9 years ago
//printf("add quote here! Qsize.%d\n",queue_size(&exchange->acceptableQ));
9 years ago
if ( exchange != 0 )
{
9 years ago
if ( instantdex_statemachinefind(myinfo,exchange,A.orderid) == 0 && instantdex_historyfind(myinfo,exchange,A.orderid) == 0 )
{
ap = calloc(1,sizeof(*ap));
*ap = A;
SETBIT(ap->peerhas,addr->addrind);
argjson = cJSON_Parse("{}");
//printf("before checkoffer Qsize.%d\n",queue_size(&exchange->acceptableQ));
if ( (retstr= instantdex_checkoffer(myinfo,&added,&txid,exchange,ap,argjson)) != 0 )
free(retstr);
if ( added == 0 )
free(ap);
free_json(argjson);
}
9 years ago
}
}
9 years ago
else
{
printf("instantdex_quote: got %llu which was already there (%p %p)\n",(long long)encodedhash.txid,ap,addr);
SETBIT(ap->peerhas,addr->addrind);
}
} else printf("instantdex_quote: checklen.%d != recvlen.%d\n",checklen,recvlen);
return(checklen);
}
void instantdex_propagate(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *ap)
{
bits256 orderhash; uint8_t serialized[8192]; int32_t i,len; struct iguana_peer *addr; struct iguana_info *coin;
orderhash = instantdex_rwoffer(1,&len,&serialized[sizeof(struct iguana_msghdr)],&ap->offer);
if ( (coin= iguana_coinfind("BTCD")) != 0 && coin->peers.numranked > 0 )
{
for (i=0; i<coin->peers.numranked; i++)
9 years ago
if ( (addr= coin->peers.ranked[i]) != 0 && addr->supernet != 0 && addr->usock >= 0 && GETBIT(ap->peerhas,addr->addrind) == 0 && strcmp("0.0.0.0",addr->ipaddr) != 0 && strcmp("127.0.0.1",addr->ipaddr) != 0 )
{
9 years ago
//SETBIT(ap->peerhas,addr->addrind);
9 years ago
char str[65]; printf("send quote.(%s) <- [%d] %s %llu\n",addr->ipaddr,len,bits256_str(str,orderhash),(long long)orderhash.txid);
9 years ago
iguana_queue_send(coin,addr,0,serialized,"quote",len,0,0);
}
}
}
9 years ago
9 years ago
// NXTrequest:
// sends NXT assetid, volume and desired
// request:
// other node sends (othercoin, othercoinaddr, otherNXT and reftx that expires well before phasedtx)
// proposal:
// NXT node submits phasedtx that refers to it, but it wont confirm
// approve:
// other node verifies unconfirmed has phasedtx and broadcasts cltv, also to NXT node, releases trigger
// confirm:
// NXT node verifies bitcoin txbytes has proper payment and cashes in with onetimepubkey
// BTC* node approves phased tx with onetimepubkey
9 years ago
bits256 instantdex_acceptset(struct instantdex_accept *ap,char *base,char *rel,int32_t duration,int32_t myside,int32_t acceptdir,double price,double volume,uint64_t account,uint32_t nonce,uint8_t minperc)
9 years ago
{
bits256 hash;
memset(ap,0,sizeof(*ap));
9 years ago
safecopy(ap->offer.base,base,sizeof(ap->offer.base));
safecopy(ap->offer.rel,rel,sizeof(ap->offer.rel));
9 years ago
if ( nonce == 0 )
OS_randombytes((uint8_t *)&ap->offer.nonce,sizeof(ap->offer.nonce));
else ap->offer.nonce = nonce;
9 years ago
if ( duration < 1000000000 )
9 years ago
ap->offer.expiration = (uint32_t)time(NULL) + duration;
else ap->offer.expiration = duration;
9 years ago
ap->offer.account = account;
9 years ago
ap->offer.myside = myside;
ap->offer.acceptdir = acceptdir;
9 years ago
ap->offer.minperc = minperc;
9 years ago
ap->offer.price64 = price * SATOSHIDEN;
ap->offer.basevolume64 = volume * SATOSHIDEN;
vcalc_sha256(0,hash.bytes,(void *)&ap->offer,sizeof(ap->offer));
9 years ago
ap->orderid = hash.txid;
9 years ago
//int32_t i;
//for (i=0; i<sizeof(ap->offer); i++)
// printf("%02x ",((uint8_t *)&ap->offer)[i]);
//printf("\n(%s/%s) %.8f %.8f acceptdir.%d myside.%d\n",base,rel,price,volume,acceptdir,myside);
9 years ago
return(hash);
}
9 years ago
int32_t instantdex_acceptextract(struct instantdex_accept *ap,cJSON *argjson)
{
9 years ago
char *base,*rel; bits256 hash,traderpub; double price,volume; int32_t baserel,acceptdir,minperc;
9 years ago
memset(ap,0,sizeof(*ap));
if ( (base= jstr(argjson,"base")) != 0 )
{
volume = jdouble(argjson,"volume");
9 years ago
if ( (minperc= juint(argjson,"minperc")) < INSTANTDEX_MINPERC )
minperc = INSTANTDEX_MINPERC;
else if ( minperc > 100 )
minperc = 100;
9 years ago
if ( (rel= jstr(argjson,"rel")) != 0 )
9 years ago
safecopy(ap->offer.rel,rel,sizeof(ap->offer.rel));
9 years ago
if ( (price= jdouble(argjson,"maxprice")) > SMALLVAL )
{
baserel = 1;
acceptdir = -1;
}
else if ( (price= jdouble(argjson,"minprice")) > SMALLVAL )
{
baserel = 0;
acceptdir = 1;
} else return(-1);
//printf("price %f vol %f baserel.%d acceptdir.%d\n",price,volume,baserel,acceptdir);
traderpub = jbits256(argjson,"traderpub");
9 years ago
hash = instantdex_acceptset(ap,base,rel,INSTANTDEX_LOCKTIME*2,baserel,acceptdir,price,volume,traderpub.txid,0,minperc);
9 years ago
}
else
{
if ( (base= jstr(argjson,"b")) != 0 )
9 years ago
safecopy(ap->offer.base,base,sizeof(ap->offer.base));
9 years ago
if ( (rel= jstr(argjson,"r")) != 0 )
9 years ago
safecopy(ap->offer.rel,rel,sizeof(ap->offer.rel));
ap->offer.nonce = juint(argjson,"n");
ap->offer.expiration = juint(argjson,"e");
ap->offer.myside = juint(argjson,"s");
ap->offer.acceptdir = jint(argjson,"d");
9 years ago
ap->offer.account = j64bits(argjson,"o");
9 years ago
ap->offer.price64 = j64bits(argjson,"p");
ap->offer.basevolume64 = j64bits(argjson,"v");
9 years ago
if ( (ap->offer.minperc= juint(argjson,"m")) < INSTANTDEX_MINPERC )
ap->offer.minperc = INSTANTDEX_MINPERC;
9 years ago
vcalc_sha256(0,hash.bytes,(void *)&ap->offer,sizeof(ap->offer));
9 years ago
ap->orderid = j64bits(argjson,"id");
}
if ( hash.txid != ap->orderid )
{
int32_t i;
for (i=0; i<sizeof(*ap); i++)
printf("%02x ",((uint8_t *)ap)[i]);
printf("instantdex_acceptextract warning %llu != %llu\n",(long long)hash.txid,(long long)ap->orderid);
return(-1);
}
return(0);
}
9 years ago
#include "swaps/iguana_BTCswap.c"
#include "swaps/iguana_ALTswap.c"
#include "swaps/iguana_NXTswap.c"
#include "swaps/iguana_PAXswap.c"
9 years ago
struct bitcoin_swapinfo *bitcoin_swapinit(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *myap,struct instantdex_accept *otherap,int32_t aminitiator,cJSON *argjson,char *statename)
9 years ago
{
9 years ago
struct bitcoin_swapinfo *swap = 0; struct iguana_info *coinbtc,*altcoin;
swap = calloc(1,sizeof(struct bitcoin_swapinfo));
9 years ago
swap->state = instantdex_statefind(BTC_states,BTC_numstates,statename);
9 years ago
swap->mine = *myap, swap->other = *otherap;
if ( (swap->isinitiator= aminitiator) != 0 )
9 years ago
{
9 years ago
swap->matched64 = otherap->orderid;
swap->expiration = otherap->offer.expiration;
9 years ago
}
else
{
9 years ago
swap->matched64 = myap->orderid;
swap->expiration = myap->offer.expiration;
9 years ago
}
9 years ago
swap->choosei = swap->otherchoosei = -1;
strcpy(swap->status,"pending");
vcalc_sha256(0,swap->myorderhash.bytes,(void *)&swap->mine.offer,sizeof(swap->mine.offer));
vcalc_sha256(0,swap->otherorderhash.bytes,(void *)&swap->other.offer,sizeof(swap->other.offer));
swap->mypubkey = myinfo->myaddr.persistent;
swap->othertrader = jbits256(argjson,"traderpub");
swap->altsatoshis = myap->offer.basevolume64;
swap->BTCsatoshis = instantdex_BTCsatoshis(myap->offer.price64,myap->offer.basevolume64);
if ( (coinbtc= iguana_coinfind("BTC")) == 0 || (altcoin= iguana_coinfind(swap->mine.offer.base)) == 0 )
9 years ago
{
9 years ago
printf("cant find BTC or %s\n",swap->mine.offer.base);
return(0);
9 years ago
}
9 years ago
swap->insurance = (swap->BTCsatoshis * INSTANTDEX_INSURANCERATE + coinbtc->chain->txfee);
swap->altpremium = (swap->altsatoshis * INSTANTDEX_INSURANCERATE + altcoin->chain->txfee);
if ( myap->offer.myside != instantdex_isbob(swap) || otherap->offer.myside == instantdex_isbob(swap) )
9 years ago
{
9 years ago
printf("isbob error.(%d %d) %d\n",myap->offer.myside,otherap->offer.myside,instantdex_isbob(swap));
return(0);
9 years ago
}
9 years ago
return(swap);
9 years ago
}
9 years ago
char *instantdex_checkoffer(struct supernet_info *myinfo,int32_t *addedp,uint64_t *txidp,struct exchange_info *exchange,struct instantdex_accept *ap,cJSON *argjson)
9 years ago
{
9 years ago
struct instantdex_accept *otherap,*tmp; struct bitcoin_swapinfo *swap; cJSON *newjson; int32_t isbob = 0;
9 years ago
*addedp = 0;
9 years ago
if ( exchange == 0 )
{
9 years ago
printf("instantdex_checkoffer null exchange\n");
return(0);
}
9 years ago
if ( instantdex_statemachinefind(myinfo,exchange,ap->orderid) != 0 || instantdex_historyfind(myinfo,exchange,ap->orderid) != 0 )
9 years ago
{
printf("instantdex_checkoffer already have statemachine or history\n");
9 years ago
return(0);
}
9 years ago
*txidp = ap->orderid;
if ( (otherap= instantdex_acceptable(myinfo,exchange,ap,ap->offer.minperc)) == 0 )
9 years ago
{
9 years ago
if ( instantdex_offerfind(myinfo,exchange,0,0,ap->orderid,ap->offer.base,ap->offer.rel,0) == 0 )
9 years ago
{
9 years ago
printf("instantdex_checkoffer add.%llu from.%llu to acceptableQ\n",(long long)ap->orderid,(long long)ap->offer.account);
instantdex_offeradd(exchange,ap);
9 years ago
*addedp = 1;
9 years ago
if ( instantdex_offerfind(myinfo,exchange,0,0,ap->orderid,ap->offer.base,ap->offer.rel,0) == 0 )
9 years ago
printf("cant find just added to acceptableQ\n");
}
9 years ago
return(jprint(instantdex_offerjson(&ap->offer,ap->orderid),1));
9 years ago
}
9 years ago
else
9 years ago
{
9 years ago
if ( otherap->offer.account == myinfo->myaddr.nxt64bits )
{
tmp = otherap;
otherap = ap;
ap = tmp;
printf("SWAP otherap\n");
}
else if ( ap->offer.account != myinfo->myaddr.nxt64bits )
{
printf("checkoffer unexpected account missing\n");
return(0);
}
isbob = ap->offer.myside;
swap = bitcoin_swapinit(myinfo,exchange,ap,otherap,1,argjson,isbob != 0 ? "BOB_sentoffer" : "ALICE_sentoffer");
9 years ago
printf("ISBOB.%d vs %d\n",isbob,instantdex_isbob(swap));
9 years ago
if ( swap != 0 )
9 years ago
{
9 years ago
printf("STATEMACHINEQ.(%llu / %llu)\n",(long long)swap->mine.orderid,(long long)swap->other.orderid);
9 years ago
//queue_enqueue("acceptableQ",&exchange->acceptableQ,&swap->DL,0);
9 years ago
instantdex_statemachineadd(exchange,swap);
9 years ago
*addedp = 1;
9 years ago
if ( (newjson= instantdex_parseargjson(myinfo,exchange,swap,argjson,1)) == 0 )
return(clonestr("{\"error\":\"instantdex_checkoffer null newjson\"}"));
9 years ago
return(instantdex_sendcmd(myinfo,&swap->mine.offer,newjson,"BTCoffer",GENESIS_PUBKEY,INSTANTDEX_HOPS,swap->deck,sizeof(swap->deck),0));
9 years ago
} else printf("error creating statemachine\n");
9 years ago
}
9 years ago
return(0);
9 years ago
}
9 years ago
char *instantdex_gotoffer(struct supernet_info *myinfo,struct exchange_info *exchange,struct instantdex_accept *myap,struct instantdex_accept *otherap,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,uint8_t *serdata,int32_t serdatalen) // receiving side
9 years ago
{
9 years ago
struct bitcoin_swapinfo *swap = 0; bits256 traderpub; struct iguana_info *coinbtc,*altcoin; cJSON *newjson=0; char *retstr=0; int32_t isbob;
9 years ago
coinbtc = iguana_coinfind("BTC");
traderpub = jbits256(argjson,"traderpub");
if ( bits256_cmp(traderpub,myinfo->myaddr.persistent) == 0 )
{
9 years ago
printf("got my own gotoffer packet orderid.%llu/%llu\n",(long long)myap->orderid,(long long)otherap->orderid);
9 years ago
return(clonestr("{\"result\":\"got my own packet\"}"));
}
9 years ago
if ( 0 )
9 years ago
{
int32_t i;
9 years ago
for (i=0; i<sizeof(otherap->offer); i++)
printf("%02x ",((uint8_t *)&otherap->offer)[i]);
printf("gotoffer.%llu\n",(long long)otherap->orderid);
9 years ago
}
9 years ago
printf(">>>>>>>>> GOTOFFER T.%d got (%s/%s) %.8f vol %.8f %llu offerside.%d offerdir.%d decksize.%d/datalen.%d\n",bits256_cmp(traderpub,myinfo->myaddr.persistent),myap->offer.base,myap->offer.rel,dstr(myap->offer.price64),dstr(myap->offer.basevolume64),(long long)myap->orderid,myap->offer.myside,myap->offer.acceptdir,(int32_t)sizeof(swap->deck),serdatalen);
9 years ago
if ( exchange == 0 )
return(clonestr("{\"error\":\"instantdex_BTCswap null exchange ptr\"}"));
9 years ago
if ( (altcoin= iguana_coinfind(myap->offer.base)) == 0 || coinbtc == 0 )
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap cant find btc or other coin info\"}"));
9 years ago
if ( strcmp(myap->offer.rel,"BTC") != 0 )
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap offer non BTC rel\"}"));
9 years ago
if ( myap->offer.expiration < (time(NULL) + INSTANTDEX_DURATION) || otherap->offer.expiration < (time(NULL) + INSTANTDEX_DURATION) )
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap offer too close to expiration\"}"));
9 years ago
isbob = myap->offer.myside;
9 years ago
if ( (swap= bitcoin_swapinit(myinfo,exchange,myap,otherap,0,argjson,isbob != 0 ? "BOB_gotoffer" : "ALICE_gotoffer")) == 0 )
return(clonestr("{\"error\":\"couldnt allocate statemachine\"}"));
9 years ago
printf("ISBOB.%d vs %d\n",isbob,instantdex_isbob(swap));
9 years ago
if ( (newjson= instantdex_parseargjson(myinfo,exchange,swap,argjson,1)) == 0 )
9 years ago
{
printf("error parsing argjson\n");
9 years ago
return(clonestr("{\"error\":\"instantdex_BTCswap offer null newjson\"}"));
9 years ago
}
9 years ago
else //if ( (retstr= instantdex_addfeetx(myinfo,newjson,ap,swap,"BOB_gotoffer","ALICE_gotoffer")) == 0 )
9 years ago
{
9 years ago
printf("create statemachine\n");
//queue_enqueue("acceptableQ",&exchange->acceptableQ,&swap->DL,0);
9 years ago
instantdex_statemachineadd(exchange,swap);
9 years ago
if ( (retstr= instantdex_choosei(swap,newjson,argjson,serdata,serdatalen)) != 0 )
9 years ago
return(retstr);
9 years ago
else
9 years ago
{
9 years ago
return(instantdex_sendcmd(myinfo,&swap->mine.offer,newjson,"BTCdeckC",traderpub,INSTANTDEX_HOPS,swap->deck,sizeof(swap->deck),0));
9 years ago
}
9 years ago
}
9 years ago
return(retstr);
}
9 years ago
char *instantdex_parse(struct supernet_info *myinfo,struct instantdex_msghdr *msg,cJSON *argjson,char *remoteaddr,uint64_t signerbits,struct instantdex_offer *offer,bits256 orderhash,uint8_t *serdata,int32_t serdatalen)
9 years ago
{
9 years ago
char cmdstr[16],*retstr; struct exchange_info *exchange; struct instantdex_accept A,*ap = 0; bits256 traderpub; cJSON *newjson; struct bitcoin_swapinfo *swap;
9 years ago
exchange = exchanges777_find("bitcoin");
9 years ago
memset(cmdstr,0,sizeof(cmdstr)), memcpy(cmdstr,msg->cmd,sizeof(msg->cmd));
if ( argjson != 0 )
{
9 years ago
traderpub = jbits256(argjson,"traderpub");
9 years ago
memset(&A,0,sizeof(A));
9 years ago
if ( j64bits(argjson,"id") != orderhash.txid )
{
9 years ago
printf("orderhash %llu (%s)\n",(long long)orderhash.txid,jprint(argjson,0));
9 years ago
return(clonestr("{\"error\":\"orderhash mismatch\"}"));
}
9 years ago
A.offer = *offer;
9 years ago
A.orderid = orderhash.txid;
9 years ago
printf("got.(%s) for %llu account.%llu serdatalen.%d\n",cmdstr,(long long)A.orderid,(long long)A.offer.account,serdatalen);
9 years ago
if ( (A.offer.minperc= jdouble(argjson,"p")) < INSTANTDEX_MINPERC )
A.offer.minperc = INSTANTDEX_MINPERC;
else if ( A.offer.minperc > 100 )
A.offer.minperc = 100;
9 years ago
if ( (swap= instantdex_statemachinefind(myinfo,exchange,A.orderid)) != 0 )
9 years ago
{
printf("found existing state machine %llu\n",(long long)A.orderid);
newjson = instantdex_parseargjson(myinfo,exchange,swap,argjson,0);
if ( serdatalen == sizeof(swap->otherdeck) && swap->choosei < 0 && (retstr= instantdex_choosei(swap,newjson,argjson,serdata,serdatalen)) != 0 )
{
printf("error choosei\n");
return(retstr);
}
return(instantdex_statemachine(BTC_states,BTC_numstates,myinfo,exchange,swap,cmdstr,argjson,newjson,serdata,serdatalen));
}
else if ( strcmp(cmdstr,"BTCoffer") == 0 ) // incoming
9 years ago
{
9 years ago
printf("BTCoffer state exchange.%p serdatalen.%d\n",exchange,serdatalen);
9 years ago
if ( (ap= instantdex_acceptable(myinfo,exchange,&A,A.offer.minperc)) != 0 )
9 years ago
{
9 years ago
if ( (retstr= instantdex_gotoffer(myinfo,exchange,ap,&A,msg,argjson,remoteaddr,signerbits,serdata,serdatalen)) != 0 ) // adds to statemachine if no error
9 years ago
{
9 years ago
printf("from GOTOFFER.(%s)\n",retstr);
return(retstr);
} else return(clonestr("{\"error\":\"gotoffer error\"}"));
9 years ago
}
else
{
9 years ago
printf("no matching trade for %s %llu -> InstantDEX_minaccept isbob.%d\n",cmdstr,(long long)A.orderid,A.offer.myside);
9 years ago
if ( instantdex_offerfind(myinfo,exchange,0,0,A.orderid,"*","*",0) == 0 )
9 years ago
{
ap = calloc(1,sizeof(*ap));
*ap = A;
9 years ago
printf("acceptableQ <- %llu\n",(long long)ap->orderid);
9 years ago
instantdex_offeradd(exchange,ap);
9 years ago
return(clonestr("{\"result\":\"added new order to orderbook\"}"));
} else return(clonestr("{\"result\":\"order was already in orderbook\"}"));
}
9 years ago
}
9 years ago
else
9 years ago
{
9 years ago
printf("cant find existing order.%llu that matches\n",(long long)A.orderid);
return(clonestr("{\"error\":\"cant find matching order\"}"));
9 years ago
}
9 years ago
}
9 years ago
return(clonestr("{\"error\":\"request needs argjson\"}"));
9 years ago
}
9 years ago
char *InstantDEX_hexmsg(struct supernet_info *myinfo,struct category_info *cat,void *ptr,int32_t len,char *remoteaddr)
9 years ago
{
9 years ago
struct instantdex_msghdr *msg = ptr; int32_t i,olen,slen,num,datalen,newlen,flag = 0;
uint8_t *serdata; struct supernet_info *myinfos[64]; struct instantdex_offer rawoffer;
9 years ago
uint64_t signerbits; uint8_t tmp[sizeof(msg->sig)]; char *retstr = 0;
bits256 orderhash,traderpub; cJSON *retjson,*item,*argjson = 0;
9 years ago
datalen = len - (int32_t)sizeof(msg->sig);
9 years ago
serdata = (void *)((long)msg + sizeof(msg->sig));
9 years ago
//printf("a signed datalen.%d allocsize.%d crc.%x\n",datalen,msg->sig.allocsize,calc_crc32(0,serdata,datalen));
9 years ago
acct777_rwsig(0,(void *)&msg->sig,(void *)tmp);
memcpy(&msg->sig,tmp,sizeof(msg->sig));
9 years ago
// printf("b signed datalen.%d allocsize.%d crc.%x\n",datalen,msg->sig.allocsize,calc_crc32(0,serdata,datalen));
9 years ago
if ( (remoteaddr == 0 || remoteaddr[0] == 0 || strcmp("127.0.0.1",remoteaddr) == 0) && ((uint8_t *)msg)[len-1] == 0 && (argjson= cJSON_Parse((char *)msg)) != 0 )
9 years ago
{
9 years ago
printf("string instantdex_hexmsg RESULT.(%s)\n",jprint(argjson,0));
9 years ago
free_json(argjson);
9 years ago
return(clonestr("{\"error\":\"string base packets deprecated\"}"));
9 years ago
}
9 years ago
else if ( (signerbits= acct777_validate(&msg->sig,acct777_msgprivkey(serdata,datalen),msg->sig.pubkey)) != 0 )//|| 1 )
9 years ago
{
flag++;
9 years ago
printf("InstantDEX_hexmsg <<<<<<<<<<<<< sigsize.%d VALIDATED [%ld] len.%d t%u allocsize.%d (%s) [%d]\n",(int32_t)sizeof(msg->sig),(long)serdata-(long)msg,datalen,msg->sig.timestamp,msg->sig.allocsize,(char *)msg->serialized,serdata[datalen-1]);
9 years ago
newlen = (int32_t)(msg->sig.allocsize - ((long)msg->serialized - (long)msg));
9 years ago
serdata = msg->serialized;
9 years ago
//printf("newlen.%d diff.%ld alloc.%d datalen.%d\n",newlen,((long)msg->serialized - (long)msg),msg->sig.allocsize,datalen);
9 years ago
if ( (argjson= cJSON_Parse((char *)serdata)) != 0 )
9 years ago
{
9 years ago
slen = (int32_t)strlen((char *)serdata) + 1;
serdata = &serdata[slen];
9 years ago
newlen -= slen;
9 years ago
}
9 years ago
if ( newlen > 0 )
9 years ago
{
9 years ago
orderhash = instantdex_rwoffer(0,&olen,serdata,&rawoffer);
9 years ago
newlen -= olen;
9 years ago
//newlen -= ((long)msg->serialized - (long)msg);
9 years ago
serdata = &serdata[olen];
9 years ago
printf("received orderhash.%llu olen.%d slen.%d newlen.%d\n",(long long)orderhash.txid,olen,slen,newlen);
9 years ago
} else olen = 0;
9 years ago
if ( newlen <= 0 )
9 years ago
serdata = 0, newlen = 0;
if ( serdata != 0 || argjson != 0 )
9 years ago
{
9 years ago
//printf("CALL instantdex_parse.(%s)\n",argjson!=0?jprint(argjson,0):"");
9 years ago
retjson = cJSON_CreateArray();
if ( (num= SuperNET_MYINFOS(myinfos,sizeof(myinfos)/sizeof(*myinfos))) == 0 )
{
myinfos[0] = myinfo;
num = 1;
}
for (i=0; i<num; i++)
{
myinfo = myinfos[i];
//char str[65]; printf("i.%d of %d: %s\n",i,num,bits256_str(str,myinfo->myaddr.persistent));
9 years ago
traderpub = jbits256(argjson,"traderpub");
if ( bits256_cmp(traderpub,myinfo->myaddr.persistent) == 0 )
continue;
9 years ago
if ( (retstr= instantdex_parse(myinfo,msg,argjson,remoteaddr,signerbits,&rawoffer,orderhash,serdata,newlen)) != 0 )
9 years ago
{
item = cJSON_CreateObject();
jaddstr(item,"result",retstr);
if ( myinfo->handle[0] != 0 )
jaddstr(item,"handle",myinfo->handle);
jaddbits256(item,"traderpub",myinfo->myaddr.persistent);
jaddi(retjson,item);
}
}
retstr = jprint(retjson,1);
9 years ago
}
9 years ago
} else printf("sig err datalen.%d\n",datalen);
9 years ago
if ( argjson != 0 )
free_json(argjson);
return(retstr);
}
9 years ago
char *instantdex_createaccept(struct supernet_info *myinfo,struct instantdex_accept **aptrp,struct exchange_info *exchange,char *base,char *rel,double price,double basevolume,int32_t acceptdir,char *mysidestr,int32_t duration,uint64_t account,uint8_t minperc)
9 years ago
{
9 years ago
struct instantdex_accept *ap; int32_t myside; char *retstr;
*aptrp = 0;
9 years ago
if ( exchange != 0 )
{
9 years ago
*aptrp = ap = calloc(1,sizeof(*ap));
9 years ago
if ( strcmp(mysidestr,base) == 0 )
myside = 0;
else if ( strcmp(mysidestr,rel) == 0 )
myside = 1;
9 years ago
else
{
myside = -1;
printf("myside.(%s) != base.%s or rel.%s\n",mysidestr,base,rel);
}
9 years ago
instantdex_acceptset(ap,base,rel,duration,myside,acceptdir,price,basevolume,account,0,minperc);
9 years ago
if ( instantdex_offerfind(myinfo,exchange,0,0,ap->orderid,ap->offer.base,ap->offer.rel,0) == 0 )
9 years ago
{
9 years ago
instantdex_propagate(myinfo,exchange,ap);
9 years ago
/*if ( queueflag != 0 )
9 years ago
{
printf("acceptableQ <- %llu\n",(long long)ap->orderid);
9 years ago
instantdex_offeradd(exchange,ap);
9 years ago
*addedp = 1;
}*/
9 years ago
retstr = jprint(instantdex_acceptjson(ap),1);
//printf("acceptableQ %llu (%s)\n",(long long)ap->orderid,retstr);
return(retstr);
} else return(0);
9 years ago
} else return(clonestr("{\"error\":\"invalid exchange\"}"));
9 years ago
}
9 years ago
void instantdex_update(struct supernet_info *myinfo)
{
struct instantdex_msghdr *pm; struct category_msg *m; char *str,remote[64]; queue_t *Q; struct queueitem *item; struct category_info *cat;
//char str2[65]; printf("myinfo->instantdex_category.(%s)\n",bits256_str(str2,myinfo->instantdex_category));
if ( (Q= category_Q(&cat,myinfo->instantdex_category,myinfo->myaddr.persistent)) != 0 && queue_size(Q) > 0 && (item= Q->list) != 0 )
9 years ago
{
9 years ago
m = queue_dequeue(Q,0);
9 years ago
pm = (struct instantdex_msghdr *)m->msg;
9 years ago
if ( m->remoteipbits != 0 )
expand_ipbits(remote,m->remoteipbits);
else remote[0] = 0;
9 years ago
{
9 years ago
char hexstr[3000];
init_hexbytes_noT(hexstr,(uint8_t *)pm,m->len);
9 years ago
printf("instantdex_update.(%s) len.%d remote.(%s) %p\n",hexstr,m->len,remote,remote);
9 years ago
}
9 years ago
if ( (str= InstantDEX_hexmsg(myinfo,cat,pm,m->len,remote)) != 0 )
free(str);
free(m);
9 years ago
}
9 years ago
}
9 years ago
#include "../includes/iguana_apidefs.h"
TWO_STRINGS_AND_TWO_DOUBLES(InstantDEX,maxaccept,base,rel,maxprice,basevolume)
9 years ago
{
9 years ago
struct instantdex_accept *ap; int32_t added; char *retstr; struct exchange_info *exchange; uint64_t txid;
9 years ago
myinfo = SuperNET_accountfind(json);
9 years ago
if ( remoteaddr == 0 && (exchange= exchanges777_find("bitcoin")) != 0 )
{
9 years ago
if ( (retstr= instantdex_createaccept(myinfo,&ap,exchange,base,rel,maxprice,basevolume,-1,rel,INSTANTDEX_OFFERDURATION,myinfo->myaddr.nxt64bits,juint(json,"minperc"))) != 0 )
free(retstr);
retstr = instantdex_checkoffer(myinfo,&added,&txid,exchange,ap,json);
if ( added == 0 )
free(ap);
return(retstr);
9 years ago
9 years ago
} else return(clonestr("{\"error\":\"InstantDEX API request only local usage!\"}"));
9 years ago
}
TWO_STRINGS_AND_TWO_DOUBLES(InstantDEX,minaccept,base,rel,minprice,basevolume)
{
9 years ago
struct instantdex_accept *ap; int32_t added; char *retstr; struct exchange_info *exchange; uint64_t txid;
9 years ago
myinfo = SuperNET_accountfind(json);
9 years ago
if ( remoteaddr == 0 && (exchange= exchanges777_find("bitcoin")) != 0 )
{
9 years ago
if ( (retstr= instantdex_createaccept(myinfo,&ap,exchanges777_find("bitcoin"),base,rel,minprice,basevolume,1,base,INSTANTDEX_OFFERDURATION,myinfo->myaddr.nxt64bits,juint(json,"minperc"))) != 0 )
free(retstr);
retstr = instantdex_checkoffer(myinfo,&added,&txid,exchange,ap,json);
if ( added == 0 )
free(ap);
return(retstr);
9 years ago
} else return(clonestr("{\"error\":\"InstantDEX API request only local usage!\"}"));
9 years ago
}
9 years ago
9 years ago
char *instantdex_statemachineget(struct supernet_info *myinfo,struct bitcoin_swapinfo **swapp,cJSON *argjson,char *remoteaddr)
9 years ago
{
9 years ago
struct bitcoin_swapinfo *swap; uint64_t orderid,otherorderid; struct exchange_info *exchange;
*swapp = 0;
if ( remoteaddr == 0 && (exchange= exchanges777_find("bitcoin")) != 0 )
9 years ago
{
9 years ago
orderid = j64bits(argjson,"myorderid");
otherorderid = j64bits(argjson,"otherid");
9 years ago
if ( (swap= instantdex_statemachinefind(myinfo,exchange,orderid)) != 0 )
9 years ago
{
if ( swap->other.orderid != otherorderid )
return(clonestr("{\"error\":\"statemachine otherid mismatch\"}"));
else
{
*swapp = swap;
return(0);
}
} else return(clonestr("{\"error\":\"statemachine not found\"}"));
9 years ago
} else return(clonestr("{\"error\":\"atomic API request only local usage!\"}"));
}
THREE_STRINGS(atomic,approve,myorderid,otherid,txname)
{
9 years ago
char *retstr,virtualevent[16]; cJSON *newjson; struct bitcoin_statetx *tx; struct bitcoin_swapinfo *swap = 0;
if ( (retstr= instantdex_statemachineget(myinfo,&swap,json,remoteaddr)) != 0 )
return(retstr);
else if ( (tx= instantdex_getstatetx(swap,txname)) == 0 )
return(clonestr("{\"error\":\"cant find txname\"}"));
else
9 years ago
{
9 years ago
strcpy(virtualevent,txname);
strcat(virtualevent,"found");
newjson = cJSON_CreateObject();
9 years ago
if ( (retstr= instantdex_sendcmd(myinfo,&swap->mine.offer,newjson,virtualevent,myinfo->myaddr.persistent,0,0,0,0)) != 0 )
9 years ago
return(retstr);
else return(clonestr("{\"result\":\"statemachine sent found event\"}"));
}
9 years ago
}
THREE_STRINGS(atomic,claim,myorderid,otherid,txname)
{
9 years ago
char *retstr; struct bitcoin_statetx *tx; struct bitcoin_swapinfo *swap = 0;
if ( (retstr= instantdex_statemachineget(myinfo,&swap,json,remoteaddr)) != 0 )
return(retstr);
else if ( (tx= instantdex_getstatetx(swap,txname)) == 0 )
return(clonestr("{\"error\":\"cant find txname\"}"));
else
9 years ago
{
9 years ago
return(clonestr("{\"result\":\"statemachine should claim tx\"}"));
}
9 years ago
}
9 years ago
THREE_STRINGS_AND_DOUBLE(tradebot,aveprice,comment,base,rel,basevolume)
{
double retvals[4],aveprice; cJSON *retjson = cJSON_CreateObject();
aveprice = instantdex_avehbla(myinfo,retvals,base,rel,basevolume);
jaddstr(retjson,"result","success");
jaddnum(retjson,"aveprice",aveprice);
jaddnum(retjson,"avebid",retvals[0]);
jaddnum(retjson,"bidvol",retvals[1]);
jaddnum(retjson,"aveask",retvals[2]);
jaddnum(retjson,"askvol",retvals[3]);
return(jprint(retjson,1));
}
9 years ago
cJSON *instantdex_reportjson(cJSON *item,char *name)
{
cJSON *newjson = cJSON_CreateObject(); uint64_t dateval;
dateval = juint(item,"timestamp"), dateval *= 1000;
newjson = cJSON_CreateObject();
jadd(newjson,name,jduplicate(jobj(item,"price")));
jadd(newjson,"volume",jduplicate(jobj(item,"volume")));
jadd(newjson,"orderid",jduplicate(jobj(item,"orderid")));
9 years ago
jadd(newjson,"account",jduplicate(jobj(item,"account")));
9 years ago
jaddnum(newjson,"date",dateval);
jaddnum(newjson,"s",dateval % 60);
9 years ago
jaddnum(newjson,"m",(dateval / 60) % 60);
jaddnum(newjson,"h",(dateval / 3600) % 24);
9 years ago
return(newjson);
}
TWO_STRINGS(InstantDEX,events,base,rel)
{
cJSON *bids,*asks,*array,*item; int32_t i,n; struct exchange_info *exchange;
array = cJSON_CreateArray();
if ( (exchange= exchanges777_find("bitcoin")) != 0 )
{
bids = cJSON_CreateArray();
asks = cJSON_CreateArray();
9 years ago
instantdex_offerfind(myinfo,exchange,bids,asks,0,base,rel,1);
9 years ago
if ( (n= cJSON_GetArraySize(bids)) > 0 )
{
for (i=0; i<n; i++)
{
9 years ago
item = jitem(bids,i);
9 years ago
jaddi(array,instantdex_reportjson(item,"bid"));
}
}
if ( (n= cJSON_GetArraySize(asks)) > 0 )
{
for (i=0; i<n; i++)
{
9 years ago
item = jitem(asks,i);
9 years ago
jaddi(array,instantdex_reportjson(item,"ask"));
}
}
free_json(bids);
free_json(asks);
}
return(jprint(array,1));
9 years ago
9 years ago
//return(clonestr("[{\"h\":14,\"m\":44,\"s\":32,\"date\":1407877200000,\"bid\":30,\"ask\":35},{\"date\":1407877200000,\"bid\":40,\"ask\":44},{\"date\":1407877200000,\"bid\":49,\"ask\":45},{\"date\":1407877200000,\"ask\":28},{\"date\":1407877200000,\"ask\":52}]"));
}
9 years ago
#include "../includes/iguana_apiundefs.h"