/****************************************************************************** * Copyright © 2014-2018 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * * holder information and the developer policies on copyright and licensing. * * * * Unless otherwise agreed in a custom licensing agreement, no part of the * * SuperNET software, including this file may be copied, modified, propagated * * or distributed except according to the terms contained in the LICENSE file * * * * Removal or modification of this copyright notice is prohibited. * * * ******************************************************************************/ #include "../iguana/iguana777.h" #include "../iguana/exchanges777.h" typedef char *basilisk_servicefunc(struct supernet_info *myinfo,char *CMD,void *addr,char *remoteaddr,uint32_t basilisktag,cJSON *valsobj,uint8_t *data,int32_t datalen,bits256 hash,int32_t from_basilisk); int32_t basilisk_notarycmd(char *cmd) { //&& strcmp(cmd,"DEX") != 0 && strcmp(cmd,"ACC") != 0 && strcmp(cmd,"RID") != 0 && if ( strcmp(cmd,"PIN") != 0 && strcmp(cmd,"OUT") != 0 && strcmp(cmd,"MSG") != 0 && strcmp(cmd,"VOT") != 0 ) return(0); else return(1); } /*int32_t basilisk_specialrelay_CMD(char *CMD) { if ( strcmp(CMD,"OUT") == 0 || strcmp(CMD,"MSG") == 0 || strcmp(CMD,"BLK") == 0 || strcmp(CMD,"MEM") == 0 || strcmp(CMD,"GTX") == 0 || strcmp(CMD,"RID") == 0 ) return(1); else return(0); }*/ cJSON *basilisk_utxosweep(struct supernet_info *myinfo,char *symbol,int64_t *satoshis,uint64_t limit,int32_t maxvins,char *coinaddr) { int32_t i,n,numvins = 0; char *retstr; uint64_t value,biggest = 0; struct iguana_info *coin=0; cJSON *item,*biggestitem=0,*array,*utxos = 0; coin = iguana_coinfind(symbol); if ( (retstr= dex_listunspent(myinfo,coin,0,0,symbol,coinaddr)) != 0 ) { //printf("(%s)\n",retstr); if ( (array= cJSON_Parse(retstr)) != 0 ) { n = cJSON_GetArraySize(array); for (i=0; i biggest ) { //fprintf(stderr,"biggest! "); if ( biggestitem != 0 ) free_json(biggestitem); biggestitem = jduplicate(item); *satoshis = biggest = value; } //else fprintf(stderr,"> "); } } free_json(array); if ( utxos == 0 && biggestitem != 0 ) { fprintf(stderr,"add biggest.(%s)\n",jprint(biggestitem,0)); jaddi(utxos,biggestitem); } } free(retstr); } return(utxos); } uint32_t basilisk_calcnonce(struct supernet_info *myinfo,uint8_t *data,int32_t datalen,uint32_t nBits) { int32_t i,numiters = 0; bits256 hash,hash2,threshold; uint32_t basilisktag; vcalc_sha256(0,hash.bytes,data,datalen); if ( nBits >= GECKO_EASIESTDIFF ) threshold = bits256_from_compact(GECKO_EASIESTDIFF); else threshold = bits256_from_compact(nBits); for (i=0; i 0 ) break; } iguana_rwnum(0,(void *)hash.uints,sizeof(basilisktag),&basilisktag); iguana_rwnum(1,&data[-(int32_t)sizeof(basilisktag)],sizeof(basilisktag),&basilisktag); //char str[65],str2[65]; printf("found hash after numiters.%d %s vs %s basilisktag.%u\n",numiters,bits256_str(str,threshold),bits256_str(str2,hash2),basilisktag); return(basilisktag); } char *basilisk_addhexstr(char **ptrp,cJSON *valsobj,char *strbuf,int32_t strsize,uint8_t *data,int32_t datalen) { *ptrp = 0; if ( data != 0 && datalen > 0 ) { if ( valsobj != 0 && jobj(valsobj,"data") != 0 ) { printf("basilisk_addhexstr warning: already have data object\n"); jdelete(valsobj,"data"); } if ( (datalen<<1)+1 > strsize ) { strbuf = calloc(1,(datalen << 1) + 1); *ptrp = (void *)strbuf; } init_hexbytes_noT(strbuf,data,datalen); if ( valsobj != 0 ) jaddstr(valsobj,"data",strbuf); } else return(0); return(strbuf); } uint8_t *get_dataptr(int32_t hdroffset,uint8_t **ptrp,int32_t *datalenp,uint8_t *space,int32_t spacesize,char *hexstr) { *ptrp = 0; uint8_t *data = 0; if ( hexstr != 0 && (*datalenp= is_hexstr(hexstr,0)) > 0 ) { *datalenp >>= 1; if ( (*datalenp+hdroffset) <= spacesize ) { memset(space,0,hdroffset); data = &space[hdroffset]; } else *ptrp = data = calloc(1,*datalenp + hdroffset); decode_hex(&data[hdroffset],*datalenp,hexstr); } if ( data != 0 ) return(&data[hdroffset]); else return(data); } uint8_t *basilisk_jsondata(int32_t extraoffset,uint8_t **ptrp,uint8_t *space,int32_t spacesize,int32_t *datalenp,char *symbol,cJSON *sendjson,uint32_t basilisktag) { char *sendstr,*hexstr=0; uint8_t *data,hexspace[4096],*allocptr=0,*hexdata=0; int32_t datalen,hexlen=0; if ( jobj(sendjson,"symbol") == 0 ) jaddstr(sendjson,"symbol",symbol); if ( (hexstr= jstr(sendjson,"data")) != 0 ) { hexdata = get_dataptr(0,&allocptr,&hexlen,hexspace,sizeof(hexspace),hexstr); //printf("jsondata.%s from sendjson\n",hexstr); jdelete(sendjson,"data"); } *ptrp = 0; sendstr = jprint(sendjson,0); datalen = (int32_t)strlen(sendstr) + 1; if ( (datalen + extraoffset + BASILISK_HDROFFSET + hexlen) <= spacesize ) data = space; else { data = calloc(1,datalen + extraoffset + BASILISK_HDROFFSET + hexlen); *ptrp = data; } data += extraoffset + BASILISK_HDROFFSET; memcpy(data,sendstr,datalen); //printf("jsondata.(%s) + hexlen.%d\n",sendstr,hexlen); free(sendstr); if ( hexlen > 0 && hexdata != 0 ) { //int32_t i; for (i=0; ibasilisktag = basilisktag; if ( (ptr->numrequired= numrequired) == 0 ) ptr->numrequired = 1; strcpy(ptr->CMD,CMD); safecopy(ptr->symbol,symbol,sizeof(ptr->symbol)); ptr->duration = timeoutmillis; ptr->expiration = OS_milliseconds() + timeoutmillis; //printf("itemcreate.%p %s %f timeout.%d\n",ptr,CMD,OS_milliseconds(),timeoutmillis); return(ptr); } int32_t basilisk_sendcmd(struct supernet_info *myinfo,char *destipaddr,char *type,uint32_t *basilisktagp,int32_t encryptflag,int32_t delaymillis,uint8_t *data,int32_t datalen,int32_t fanout,uint32_t nBits) // data must be offset by sizeof(iguana_msghdr)+sizeof(basilisktag) { int32_t i,l,s,valid,val,n=0,retval = -1; char cmd[12]; struct iguana_info *coin,*tmp; struct iguana_peer *addr; bits256 hash; uint32_t *alreadysent,r; if ( fanout <= 0 ) fanout = sqrt(myinfo->NOTARY.NUMRELAYS) + 1; else if ( fanout > BASILISK_MAXFANOUT ) fanout = BASILISK_MAXFANOUT; if ( type == 0 ) type = "INF"; if ( strlen(type) > 3 ) { printf("basilisk_sendcmd illegal type(%s)\n",type); return(-1); } if ( destipaddr != 0 ) { if ( destipaddr[0] == 0 ) { destipaddr = 0; // broadcast } else if ( strcmp(destipaddr,"127.0.0.1") == 0 || strcmp(destipaddr,myinfo->ipaddr) == 0 ) { printf("return after locally basilisk_msgprocess\n"); hash = GENESIS_PUBKEY; basilisk_msgprocess(myinfo,0,0,type,*basilisktagp,data,datalen); return(0); } } iguana_rwnum(1,&data[-(int32_t)sizeof(*basilisktagp)],sizeof(*basilisktagp),basilisktagp); if ( *basilisktagp == 0 ) { if ( nBits != 0 ) *basilisktagp = basilisk_calcnonce(myinfo,data,datalen,nBits); else *basilisktagp = rand(); iguana_rwnum(1,&data[-(int32_t)sizeof(*basilisktagp)],sizeof(*basilisktagp),basilisktagp); } data -= sizeof(*basilisktagp), datalen += sizeof(*basilisktagp); memset(cmd,0,sizeof(cmd)); sprintf(cmd,"SuperNET%s",type); if ( destipaddr != 0 ) { cmd[6] = 'E', cmd[7] = 'T'; HASH_ITER(hh,myinfo->allcoins,coin,tmp) { if ( coin->peers == 0 ) continue; if ( coin->FULLNODE == 0 && coin->VALIDATENODE == 0 ) cmd[0] = 's'; else cmd[0] = 'S'; for (i=0; ipeers->active[i]; if ( addr->usock >= 0 && strcmp(addr->ipaddr,destipaddr) == 0 ) { return(iguana_queue_send(addr,delaymillis,&data[-(int32_t)sizeof(struct iguana_msghdr)],cmd,datalen)); } } } return(-1); } if ( basilisk_notarycmd(type) != 0 && myinfo->NOTARY.NUMRELAYS == 0 ) { //printf("no notary nodes to send (%s) to\n",type); return(-1); } //portable_mutex_lock(&myinfo->allcoins_mutex); //dex_reqsend(myinfo,&data[-(int32_t)sizeof(struct iguana_msghdr)],datalen); alreadysent = calloc(IGUANA_MAXPEERS * IGUANA_MAXCOINS,sizeof(*alreadysent)); HASH_ITER(hh,myinfo->allcoins,coin,tmp) { if ( coin->peers == 0 ) continue; if ( basilisk_notarycmd(type) != 0 && strcmp(coin->symbol,"RELAY") != 0 ) continue; if ( coin->FULLNODE == 0 && coin->VALIDATENODE == 0 ) cmd[0] = 's'; else cmd[0] = 'S'; r = rand() % IGUANA_MAXPEERS; for (l=0; lpeers->active[i]; if ( addr->supernet != 0 || addr->basilisk != 0 ) valid = 1; else valid = 0; if ( addr->usock >= 0 ) { s = 0; valid = (addr->supernet != 0); if ( basilisk_notarycmd(type) != 0 || (strcmp(type,"INF") == 0 && strcmp(coin->symbol,"RELAY") == 0) ) { valid = 0; /*OS_randombytes((void *)&r2,sizeof(r2)); if ( (r2 % myinfo->NOTARY.NUMRELAYS) >= sqrt(myinfo->NOTARY.NUMRELAYS) ) { printf("fanout.%d s.%d n.%d skip %s\n",fanout,s,n,addr->ipaddr); continue; }*/ for (s=0; sNOTARY.NUMRELAYS; s++) if ( addr->ipbits != myinfo->myaddr.myipbits && myinfo->NOTARY.RELAYS[s].ipbits == addr->ipbits ) break; if ( s == myinfo->NOTARY.NUMRELAYS ) { //printf("skip non-relay.(%s)\n",addr->ipaddr); continue; } valid = 1; //printf("send to other relay.(%s)\n",addr->ipaddr); } for (s=0; sipbits ) { //printf("already sent to %s\n",addr->ipaddr); continue; } if ( s == n && valid == 1 && (destipaddr == 0 || strcmp(addr->ipaddr,destipaddr) == 0) ) { val = 0; //fprintf(stderr,">>> (%s).%u ",addr->ipaddr,coin->chain->portp2p); //printf("n.%d/fanout.%d i.%d l.%d [%s].tag%u send %s [%x] datalen.%d addr->supernet.%u basilisk.%u to (%s).%d destip.%s\n",n,fanout,i,l,cmd,*(uint32_t *)data,type,*(int32_t *)&data[datalen-4],datalen,addr->supernet,addr->basilisk,addr->ipaddr,addr->A.port,destipaddr!=0?destipaddr:"broadcast"); if ( encryptflag != 0 && bits256_nonz(addr->pubkey) != 0 ) { void *ptr; uint8_t *cipher,space[8192]; int32_t cipherlen; bits256 privkey; cmd[6] = 'e', cmd[7] = 't'; memset(privkey.bytes,0,sizeof(privkey)); if ( (cipher= SuperNET_ciphercalc(&ptr,&cipherlen,&privkey,&addr->pubkey,data,datalen,space,sizeof(space))) != 0 ) { if ( (val= iguana_queue_send(addr,delaymillis,&cipher[-(int32_t)sizeof(struct iguana_msghdr)],cmd,cipherlen)) >= cipherlen ) alreadysent[n++] = (uint32_t)addr->ipbits; if ( ptr != 0 ) free(ptr); } } else { cmd[6] = 'E', cmd[7] = 'T'; if ( (val= iguana_queue_send(addr,delaymillis,&data[-(int32_t)sizeof(struct iguana_msghdr)],cmd,datalen)) >= datalen ) { alreadysent[n++] = (uint32_t)addr->ipbits; if ( n >= IGUANA_MAXPEERS*IGUANA_MAXCOINS ) break; } } if ( destipaddr != 0 || (fanout > 0 && n >= fanout) ) { free(alreadysent); return(val); } else if ( val > retval ) retval = val; } } } if ( n >= IGUANA_MAXPEERS*IGUANA_MAXCOINS ) break; } //portable_mutex_unlock(&myinfo->allcoins_mutex); free(alreadysent); return(n); } void basilisk_sendback(struct supernet_info *myinfo,char *origCMD,char *symbol,char *remoteaddr,uint32_t basilisktag,char *retstr) { uint8_t *data,space[4096],*allocptr; struct iguana_info *virt; cJSON *valsobj; int32_t datalen,encryptflag=0,delaymillis=0; //printf("%s retstr.(%s) -> remote.(%s) basilisktag.%u\n",origCMD,retstr,remoteaddr,basilisktag); if ( retstr != 0 && remoteaddr != 0 && remoteaddr[0] != 0 && strcmp(remoteaddr,"127.0.0.1") != 0 ) { if ( (valsobj= cJSON_Parse(retstr)) != 0 ) { jaddstr(valsobj,"origcmd",origCMD); jaddstr(valsobj,"symbol",symbol); if ( myinfo->ipaddr[0] != 0 ) jaddstr(valsobj,"relay",myinfo->ipaddr); jaddnum(valsobj,"timestamp",(uint32_t)time(NULL)); if ( (virt= iguana_coinfind(symbol)) != 0 ) { jaddnum(valsobj,"hwm",virt->blocks.hwmchain.height); if ( bits256_nonz(virt->blocks.hwmchain.RO.hash2) != 0 ) jaddbits256(valsobj,"chaintip",virt->blocks.hwmchain.RO.hash2); } data = basilisk_jsondata(sizeof(struct iguana_msghdr),&allocptr,space,sizeof(space),&datalen,symbol,valsobj,basilisktag); //printf("sendback.%d -> %s\n",datalen,remoteaddr); basilisk_sendcmd(myinfo,remoteaddr,"RET",&basilisktag,encryptflag,delaymillis,data,datalen,0,0); if ( allocptr != 0 ) free(allocptr); free_json(valsobj); } } } struct basilisk_item *basilisk_issueremote(struct supernet_info *myinfo,struct iguana_peer *addr,int32_t *numsentp,char *CMD,char *symbol,int32_t blockflag,cJSON *valsobj,int32_t fanout,int32_t numrequired,uint32_t basilisktag,int32_t timeoutmillis,void *deprecated_dontuse,char *retstr,int32_t encryptflag,int32_t delaymillis,uint32_t nBits) { struct basilisk_item *pending; uint8_t *allocptr,*data,space[4096]; int32_t datalen; pending = basilisk_itemcreate(myinfo,CMD,symbol,basilisktag,numrequired,valsobj,timeoutmillis,0); pending->nBits = nBits; *numsentp = 0; if ( retstr != 0 ) { pending->retstr = retstr; pending->numresults = pending->numrequired; } else { valsobj = jduplicate(valsobj); data = basilisk_jsondata(sizeof(struct iguana_msghdr),&allocptr,space,sizeof(space),&datalen,symbol,valsobj,basilisktag); free_json(valsobj), valsobj = 0; *numsentp = pending->numsent = basilisk_sendcmd(myinfo,addr != 0 ? addr->ipaddr : 0,CMD,&pending->basilisktag,encryptflag,delaymillis,data,datalen,fanout,pending->nBits); if ( blockflag != 0 ) { portable_mutex_lock(&myinfo->basilisk_mutex); HASH_ADD(hh,myinfo->basilisks.issued,basilisktag,sizeof(basilisktag),pending); portable_mutex_unlock(&myinfo->basilisk_mutex); if ( pending->expiration <= OS_milliseconds() ) pending->expiration = OS_milliseconds() + pending->duration; strcpy(pending->symbol,"RELAY"); strcpy(pending->CMD,CMD); //printf("block for %f\n",pending->expiration - OS_milliseconds()); while ( OS_milliseconds() < pending->expiration ) { portable_mutex_lock(&myinfo->basilisk_mutex); if ( pending->numresults >= pending->numrequired ) { portable_mutex_unlock(&myinfo->basilisk_mutex); //printf("%p <<<<<<<<<<<<< numresults.%d vs numrequired.%d\n",pending,pending->numresults,pending->numrequired); break; } portable_mutex_unlock(&myinfo->basilisk_mutex); usleep(10000); } } if ( allocptr != 0 ) free(allocptr); } return(pending); } struct basilisk_item *basilisk_requestservice(struct supernet_info *myinfo,struct iguana_peer *addr,char *CMD,int32_t blockflag,cJSON *valsobj,bits256 hash,uint8_t *data,int32_t datalen,uint32_t nBits) { int32_t minfanout,numrequired,timeoutmillis,numsent,delaymillis,encryptflag,fanout; struct basilisk_item *ptr; char buf[4096],*symbol,*str = 0; struct iguana_info *virt; //printf("request.(%s)\n",jprint(valsobj,0)); basilisk_addhexstr(&str,valsobj,buf,sizeof(buf),data,datalen); if ( str != 0 ) free(str); if ( bits256_nonz(hash) == 0 || (bits256_cmp(hash,GENESIS_PUBKEY) != 0 && bits256_nonz(hash) != 0) ) { if ( jobj(valsobj,"hash") != 0 ) jdelete(valsobj,"hash"); jaddbits256(valsobj,"hash",hash); } if ( (timeoutmillis= jint(valsobj,"timeout")) == 0 ) timeoutmillis = BASILISK_TIMEOUT; minfanout = sqrt(myinfo->NOTARY.NUMRELAYS)+1; if ( minfanout < 8 ) minfanout = 8; if ( jobj(valsobj,"fanout") == 0 ) fanout = minfanout; else fanout = jint(valsobj,"fanout"); if ( fanout < minfanout ) fanout = minfanout; if ( (numrequired= jint(valsobj,"numrequired")) <= 0 ) numrequired = MIN(fanout/2,sqrt(myinfo->NOTARY.NUMRELAYS)+1); if ( (symbol= jstr(valsobj,"coin")) != 0 || (symbol= jstr(valsobj,"symbol")) != 0 ) { if ( (virt= iguana_coinfind(symbol)) != 0 ) { jaddstr(valsobj,"symbol",symbol); jaddnum(valsobj,"longest",virt->longestchain); jaddnum(valsobj,"hwm",virt->blocks.hwmchain.height); } } if ( symbol == 0 ) symbol = "RELAY"; encryptflag = jint(valsobj,"encrypt"); delaymillis = jint(valsobj,"delay"); ptr = basilisk_issueremote(myinfo,addr,&numsent,CMD,symbol,blockflag,valsobj,fanout,numrequired,0,timeoutmillis,0,0,encryptflag,delaymillis,nBits); return(ptr); } char *basilisk_standardservice(char *CMD,struct supernet_info *myinfo,void *_addr,bits256 hash,cJSON *valsobj,char *hexstr,int32_t blockflag) // client side { uint32_t nBits = 0; uint8_t space[4096],*allocptr=0,*data = 0; struct basilisk_item *ptr; int32_t i,datalen = 0; cJSON *retjson; char *retstr=0; if ( myinfo->IAMNOTARY != 0 && myinfo->NOTARY.RELAYID >= 0 && (strcmp(CMD,"INF") != 0 && basilisk_notarycmd(CMD) == 0) ) return(clonestr("{\"error\":\"unsupported special relay command\"}")); data = get_dataptr(BASILISK_HDROFFSET,&allocptr,&datalen,space,sizeof(space),hexstr); //printf("request.(%s)\n",jprint(valsobj,0)); ptr = basilisk_requestservice(myinfo,_addr,CMD,blockflag,valsobj,hash,data,datalen,nBits); if ( allocptr != 0 ) free(allocptr); if ( ptr != 0 ) { if ( (retstr= ptr->retstr) != 0 ) ptr->retstr = 0; else { if ( ptr->numresults > 0 ) { retjson = cJSON_CreateArray(); for (i=0; inumresults; i++) jaddi(retjson,ptr->results[i]), ptr->results[i] = 0; //printf("numresults.%d (%p)\n",ptr->numresults,ptr); } else { retjson = cJSON_CreateObject(); if ( ptr->numsent > 0 ) { //queue_enqueue("submitQ",&myinfo->basilisks.submitQ,&ptr->DL,0); jaddstr(retjson,"result","error"); jaddnum(retjson,"packetsize",ptr->numsent); } else jaddstr(retjson,"error","didnt find any nodes to send to"); } retstr = jprint(retjson,1); } ptr->finished = OS_milliseconds() + 10000; } if ( (0) && strcmp("MSG",CMD) == 0 ) printf("%s.(%s) -> (%s)\n",CMD,jprint(valsobj,0),retstr!=0?retstr:""); return(retstr); } int32_t basilisk_relayid(struct supernet_info *myinfo,uint32_t ipbits) { int32_t j; for (j=0; jNOTARY.NUMRELAYS; j++) if ( myinfo->NOTARY.RELAYS[j].ipbits == ipbits ) return(j); return(-1); } #include "basilisk_bitcoin.c" #include "basilisk_nxt.c" #include "basilisk_ether.c" #include "basilisk_waves.c" #include "basilisk_lisk.c" #include "smartaddress.c" #include "basilisk_MSG.c" #include "tradebots_marketmaker.c" #include "tradebots_liquidity.c" #include "basilisk_tradebot.c" #include "basilisk_swap.c" #include "basilisk_DEX.c" #include "basilisk_ping.c" #include "basilisk_vote.c" #include "basilisk_CMD.c" #include "jumblr.c" void basilisk_functions(struct iguana_info *coin,int32_t protocol) { coin->protocol = protocol; switch ( protocol ) { /*case IGUANA_PROTOCOL_BITCOIN: coin->basilisk_balances = basilisk_bitcoinbalances; coin->basilisk_rawtx = basilisk_bitcoinrawtx; //coin->basilisk_rawtxmetric = basilisk_bitcoin_rawtxmetric; coin->basilisk_value = basilisk_bitcoinvalue; coin->basilisk_valuemetric = basilisk_bitcoin_valuemetric; break; case IGUANA_PROTOCOL_IOTA: coin->basilisk_balances = basilisk_iotabalances; coin->basilisk_rawtx = basilisk_iotarawtx; break; case IGUANA_PROTOCOL_NXT: coin->basilisk_balances = basilisk_nxtbalances; coin->basilisk_rawtx = basilisk_nxtrawtx; break; case IGUANA_PROTOCOL_ETHER: coin->basilisk_balances = basilisk_etherbalances; coin->basilisk_rawtx = basilisk_etherrawtx; break; case IGUANA_PROTOCOL_WAVES: coin->basilisk_balances = basilisk_wavesbalances; coin->basilisk_rawtx = basilisk_wavesrawtx; break; case IGUANA_PROTOCOL_LISK: coin->basilisk_balances = basilisk_liskbalances; coin->basilisk_rawtx = basilisk_liskrawtx; break;*/ } } int32_t basilisk_hashes_send(struct supernet_info *myinfo,struct iguana_info *virt,struct iguana_peer *addr,char *CMD,bits256 *hashes,int32_t num) { bits256 hash; uint8_t *serialized; int32_t i,len = 0; char *str=0,*retstr,*hexstr,space[4096]; bits256 txid; cJSON *vals; if ( virt != 0 && addr != 0 ) { memset(hash.bytes,0,sizeof(hash)); serialized = (void *)hashes; for (i=0; isymbol); if ( (retstr= basilisk_standardservice(CMD,myinfo,addr,hash,vals,hexstr,0)) != 0 ) free(retstr); free_json(vals); if ( str != 0 ) free(str); } return(0); } else return(-1); } void basilisk_geckoresult(struct supernet_info *myinfo,char *remoteaddr,char *retstr,uint8_t *data,int32_t datalen) { struct iguana_info *virt; char *symbol,*str,*type; cJSON *retjson; bits256 hash2; if ( retstr != 0 && (retjson= cJSON_Parse(retstr)) != 0 ) { if ( (symbol= jstr(retjson,"symbol")) != 0 && (virt= iguana_coinfind(symbol)) != 0 ) { if ( data != 0 ) { str = 0; if ( (type= jstr(retjson,"type")) != 0 ) { hash2 = jbits256(retjson,"hash"); if ( strcmp(type,"HDR") == 0 && virt->virtualchain != 0 ) str = gecko_headersarrived(myinfo,virt,remoteaddr,data,datalen,hash2); else if ( strcmp(type,"MEM") == 0 && virt->virtualchain != 0 ) str = gecko_mempoolarrived(myinfo,virt,remoteaddr,data,datalen,hash2); else if ( strcmp(type,"BLK") == 0 && virt->virtualchain != 0 ) str = gecko_blockarrived(myinfo,virt,remoteaddr,data,datalen,hash2,0); else if ( strcmp(type,"GTX") == 0 && virt->virtualchain != 0 ) str = gecko_txarrived(myinfo,virt,remoteaddr,data,datalen,hash2); } if ( str != 0 ) free(str); } } free_json(retjson); } } void basilisk_result(struct supernet_info *myinfo,char *remoteaddr,uint32_t basilisktag,cJSON *vals,uint8_t *data,int32_t datalen) { char *retstr,CMD[16]; struct basilisk_item *pending; cJSON *item; if ( vals != 0 ) { retstr = jprint(vals,0); safecopy(CMD,jstr(vals,"origcmd"),sizeof(CMD)); //if ( 0 && strcmp("RID",CMD) != 0 ) //printf("(%s) -> Q.%u results vals.(%s)\n",CMD,basilisktag,retstr);//(int32_t)strlen(retstr)); if ( strcmp(CMD,"GET") == 0 ) basilisk_geckoresult(myinfo,remoteaddr,retstr,data,datalen); else { portable_mutex_lock(&myinfo->basilisk_mutex); HASH_FIND(hh,myinfo->basilisks.issued,&basilisktag,sizeof(basilisktag),pending); portable_mutex_unlock(&myinfo->basilisk_mutex); if ( pending != 0 && retstr != 0 ) { if ( (item= cJSON_Parse(retstr)) != 0 ) { if ( jobj(item,"myip") == 0 ) jaddstr(item,"myip",remoteaddr); if ( pending->numresults < sizeof(pending->results)/sizeof(*pending->results) ) { //printf("%p.(%s).%d\n",pending,jprint(item,0),pending->numresults); pending->results[pending->numresults++] = item; } } else printf("couldnt parse.(%s)\n",retstr); } //else printf("couldnt find issued.%u\n",basilisktag); } free(retstr); } } void basilisk_wait(struct supernet_info *myinfo,struct iguana_info *coin) { if ( coin != 0 ) { while ( coin->basilisk_busy != 0 ) usleep(1000); } else { while ( myinfo->basilisk_busy != 0 ) usleep(1000); } } void basilisk_msgprocess(struct supernet_info *myinfo,void *_addr,uint32_t senderipbits,char *type,uint32_t basilisktag,uint8_t *data,int32_t datalen) { cJSON *valsobj; char *symbol,*retstr=0,remoteaddr[64],CMD[4],cmd[4]; int32_t height,origlen,from_basilisk,i,timeoutmillis,flag,numrequired,jsonlen; uint8_t *origdata; struct iguana_info *coin=0; bits256 hash; struct iguana_peer *addr = _addr; static basilisk_servicefunc *basilisk_services[][2] = { { (void *)"OUT", &basilisk_respond_OUT }, // send MSG to hash/id/num { (void *)"MSG", &basilisk_respond_MSG }, // get MSG (hash, id, num) { (void *)"ADD", &basilisk_respond_addrelay }, // relays register with each other bus { (void *)"VOT", &basilisk_respond_VOT }, // VOTE handler for something //{ (void *)"PIN", &basilisk_respond_PIN }, // encrypted data for jumblr { (void *)"HOP", &basilisk_respond_forward }, // message forwarding { (void *)"BOX", &basilisk_respond_mailbox }, // create/send/check mailbox pubkey // small virtual private network { (void *)"VPN", &basilisk_respond_VPNcreate }, // create virtual network's hub via privkey { (void *)"ARC", &basilisk_respond_VPNjoin }, // join { (void *)"GAB", &basilisk_respond_VPNmessage }, // private message { (void *)"SAY", &basilisk_respond_VPNbroadcast }, // broadcast { (void *)"EAR", &basilisk_respond_VPNreceive }, // network receive (via poll) { (void *)"END", &basilisk_respond_VPNlogout }, // logout //{ (void *)"DEX", &basilisk_respond_DEX }, //{ (void *)"RID", &basilisk_respond_RID }, //{ (void *)"ACC", &basilisk_respond_ACC }, { (void *)"BYE", &basilisk_respond_goodbye }, // disconnect // gecko chains { (void *)"GET", &basilisk_respond_geckoget }, // requests headers, block or tx { (void *)"HDR", &basilisk_respond_geckoheaders }, // reports headers { (void *)"BLK", &basilisk_respond_geckoblock }, // reports virtchain block { (void *)"MEM", &basilisk_respond_mempool }, // reports virtchain mempool { (void *)"GTX", &basilisk_respond_geckotx }, // reports virtchain tx // coin services { (void *)"VAL", &basilisk_respond_value }, { (void *)"BAL", &basilisk_respond_balances }, { (void *)"INF", &basilisk_respond_getinfo }, }; strncpy(CMD,type,3), CMD[3] = cmd[3] = 0; if ( isupper((int32_t)CMD[0]) != 0 && isupper((int32_t)CMD[1]) != 0 && isupper((int32_t)CMD[2]) != 0 ) from_basilisk = 1; else from_basilisk = 0; origdata = data; origlen = datalen; for (i=0; i<3; i++) { CMD[i] = toupper((int32_t)CMD[i]); cmd[i] = tolower((int32_t)CMD[i]); } if ( myinfo->IAMNOTARY != 0 )//RELAYID >= 0 ) { if ( basilisk_notarycmd(CMD) == 0 && strcmp(CMD,"INF") != 0 ) return; } else if ( basilisk_notarycmd(CMD) != 0 ) return; symbol = "RELAY"; if ( senderipbits == 0 ) expand_ipbits(remoteaddr,myinfo->myaddr.myipbits); else expand_ipbits(remoteaddr,senderipbits); if ( (valsobj= cJSON_Parse((char *)data)) != 0 ) { if ( jobj(valsobj,"coin") != 0 ) coin = iguana_coinfind(jstr(valsobj,"coin")); else if ( jobj(valsobj,"symbol") != 0 ) coin = iguana_coinfind(jstr(valsobj,"symbol")); if ( coin != 0 ) { if ( (height= juint(valsobj,"hwm")) > 0 ) { if ( height > addr->height ) addr->height = height; if ( height > coin->longestchain ) coin->longestchain = height; } } if ( strcmp(type,"RET") == 0 ) { basilisk_result(myinfo,remoteaddr,basilisktag,valsobj,data,datalen); return; } } else { printf("unexpected binary packet datalen.%d\n",datalen); return; } for (i=flag=0; ibasilisk_busy = 1; if ( valsobj != 0 ) { jsonlen = (int32_t)strlen((char *)data) + 1; if ( datalen > jsonlen ) data += jsonlen, datalen -= jsonlen; else data = 0, datalen = 0; if ( coin == 0 ) coin = iguana_coinfind(symbol); if ( coin != 0 ) { symbol = coin->symbol; coin->basilisk_busy = 1; } hash = jbits256(valsobj,"hash"); timeoutmillis = jint(valsobj,"timeout"); if ( (numrequired= jint(valsobj,"numrequired")) == 0 ) numrequired = sqrt(myinfo->NOTARY.NUMRELAYS)+1; if ( senderipbits != 0 ) expand_ipbits(remoteaddr,senderipbits); else remoteaddr[0] = 0; for (i=0; iFULLNODE > 0) || myinfo->NOTARY.RELAYID >= 0 ) // iguana node { //printf("\n call %s from_basilisk.%d (%s)\n",addr->ipaddr,from_basilisk,type); if ( (retstr= (*basilisk_services[i][1])(myinfo,type,addr,remoteaddr,basilisktag,valsobj,data,datalen,hash,from_basilisk)) != 0 ) { //printf("%s from_basilisk.%d ret.(%s)\n",addr->ipaddr,from_basilisk,retstr); //if ( from_basilisk != 0 || strcmp(CMD,"GET") == 0 ) basilisk_sendback(myinfo,CMD,symbol,remoteaddr,basilisktag,retstr); if ( retstr != 0 ) free(retstr); break; } else printf("services null return\n"); } else printf("non-relay got %s unhandled.(%s)\n",coin!=0?coin->symbol:"",type); } } free_json(valsobj); } if ( coin != 0 ) coin->basilisk_busy = 0; myinfo->basilisk_busy = 0; } int32_t basilisk_p2pQ_process(struct supernet_info *myinfo,int32_t maxiters) { struct basilisk_p2pitem *ptr; char senderip[64]; uint32_t n=0,basilisktag,len; while ( n < maxiters && (ptr= queue_dequeue(&myinfo->p2pQ)) != 0 ) { len = 0; expand_ipbits(senderip,ptr->ipbits); //printf("p2p.%d from.(%s) %c%c%c datalen.%d\n",n,senderip,ptr->type[0],ptr->type[1],ptr->type[2],ptr->datalen); if ( ptr->type[0] == 'P' && ptr->type[1] == 'I' && ptr->type[2] == 'N' ) { if ( myinfo->NOTARY.RELAYID >= 0 ) { //printf("process ping\n"); basilisk_ping_process(myinfo,ptr->addr,ptr->ipbits,ptr->data,ptr->datalen); //printf("done process ping\n"); } } else { len += iguana_rwnum(0,ptr->data,sizeof(basilisktag),&basilisktag); if ( (0) && myinfo->IAMLP == 0 ) printf("RELAYID.%d ->received.%d basilisk_p2p.(%s) from %s tag.%u\n",myinfo->NOTARY.RELAYID,ptr->datalen,ptr->type,senderip,basilisktag); basilisk_msgprocess(myinfo,ptr->addr,ptr->ipbits,ptr->type,basilisktag,&ptr->data[len],ptr->datalen - len); if ( (0) && myinfo->IAMLP == 0 ) printf("processed.%s from %s\n",ptr->type,senderip); } free(ptr); n++; } return(n); } struct basilisk_p2pitem *basilisk_p2pitem_create(struct iguana_info *coin,struct iguana_peer *addr,char *type,uint32_t ipbits,uint8_t *data,int32_t datalen) { struct basilisk_p2pitem *ptr; ptr = calloc(1,sizeof(*ptr) + datalen + 16); ptr->coin = coin; ptr->addr = addr; ptr->ipbits = ipbits; ptr->datalen = datalen; safecopy(ptr->type,type,sizeof(ptr->type)); memcpy(ptr->data,data,datalen); return(ptr); } void basilisk_p2p(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,char *senderip,uint8_t *data,int32_t datalen,char *type,int32_t encrypted) { uint32_t ipbits; int32_t msglen; void *ptr = 0; uint8_t space[4096]; bits256 senderpub; ipbits = (uint32_t)calc_ipbits(senderip); if ( encrypted != 0 ) { printf("encrypted p2p\n"); memset(senderpub.bytes,0,sizeof(senderpub)); if ( (data= SuperNET_deciphercalc(&ptr,&msglen,myinfo->privkey,senderpub,data,datalen,space,sizeof(space))) == 0 ) { printf("basilisk_p2p decrytion error\n"); return; } else datalen = msglen; if ( ptr != 0 ) free(ptr); } if ( senderip != 0 && senderip[0] != 0 && strcmp(senderip,"127.0.0.1") != 0 ) ipbits = (uint32_t)calc_ipbits(senderip); else ipbits = myinfo->myaddr.myipbits; ptr = basilisk_p2pitem_create(coin,addr,type,ipbits,data,datalen); queue_enqueue("p2pQ",&myinfo->p2pQ,ptr); } int32_t basilisk_issued_purge(struct supernet_info *myinfo,int32_t timepad) { struct basilisk_item *tmp,*pending; cJSON *item; int32_t i,n = 0; double startmilli = OS_milliseconds(); portable_mutex_lock(&myinfo->basilisk_mutex); HASH_ITER(hh,myinfo->basilisks.issued,pending,tmp) { if ( pending != 0 && ((pending->finished > 0 && startmilli > pending->finished) || startmilli > pending->expiration+timepad) ) { HASH_DELETE(hh,myinfo->basilisks.issued,pending); //printf("%f > %f (%d) clear pending.%p numresults.%d %p\n",startmilli,pending->expiration+timepad,timepad,pending,pending->numresults,pending->retstr); for (i=0; inumresults; i++) if ( (item= pending->results[i]) != 0 ) free_json(item); if ( pending->retstr != 0 ) free(pending->retstr); memset(pending,0,sizeof(*pending)); free(pending); n++; } } portable_mutex_unlock(&myinfo->basilisk_mutex); return(n); } void basilisks_loop(void *arg) { static uint32_t counter; struct iguana_info *relay; struct supernet_info *myinfo = arg; int32_t i,iter; double startmilli,endmilli; struct dpow_info *dp; iter = 0; relay = iguana_coinfind("RELAY"); printf("start basilisk loop\n"); while ( 1 ) { if ( relay == 0 ) relay = iguana_coinfind("RELAY"); startmilli = OS_milliseconds(); endmilli = startmilli + 1000; //fprintf(stderr,"A "); basilisk_issued_purge(myinfo,600000); //fprintf(stderr,"B "); basilisk_p2pQ_process(myinfo,777); //fprintf(stderr,"C "); if ( myinfo->IAMNOTARY != 0 ) { if ( relay != 0 ) { //fprintf(stderr,"D "); basilisk_ping_send(myinfo,relay); } counter++; //fprintf(stderr,"E "); if ( myinfo->numdpows == 1 ) { iguana_dPoWupdate(myinfo,myinfo->DPOWS[0]); endmilli = startmilli + 100; } else if ( myinfo->numdpows > 1 ) { dp = myinfo->DPOWS[counter % myinfo->numdpows]; iguana_dPoWupdate(myinfo,dp); //if ( (counter % myinfo->numdpows) != 0 ) { //fprintf(stderr,"F "); iguana_dPoWupdate(myinfo,myinfo->DPOWS[0]); } endmilli = startmilli + 30; } //fprintf(stderr,"F "); } else { //fprintf(stderr,"G "); dex_updateclient(myinfo); if ( myinfo->IAMLP != 0 ) endmilli = startmilli + 500; else endmilli = startmilli + 1000; } if ( myinfo->expiration != 0 && (myinfo->dexsock >= 0 || myinfo->IAMLP != 0 || myinfo->DEXactive > time(NULL)) ) { //fprintf(stderr,"H "); for (i=0; i<100; i++) if ( basilisk_requests_poll(myinfo) <= 0 ) break; } //printf("RELAYID.%d endmilli %f vs now %f\n",myinfo->NOTARY.RELAYID,endmilli,startmilli); while ( OS_milliseconds() < endmilli ) usleep(10000); //printf("finished waiting numdpow.%d\n",myinfo->numdpows); iter++; } } void basilisks_init(struct supernet_info *myinfo) { iguana_initQ(&myinfo->p2pQ,"p2pQ"); iguana_initQ(&myinfo->msgQ,"messageQ"); portable_mutex_init(&myinfo->bu_mutex); portable_mutex_init(&myinfo->allcoins_mutex); portable_mutex_init(&myinfo->basilisk_mutex); portable_mutex_init(&myinfo->smart_mutex); portable_mutex_init(&myinfo->DEX_mutex); portable_mutex_init(&myinfo->DEX_swapmutex); portable_mutex_init(&myinfo->DEX_reqmutex); portable_mutex_init(&myinfo->gecko_mutex); portable_mutex_init(&myinfo->messagemutex); myinfo->basilisks.launched = iguana_launch(iguana_coinfind("BTCD"),"basilisks_loop",basilisks_loop,myinfo,IGUANA_PERMTHREAD); printf("Basilisk initialized\n"); } #include "../includes/iguana_apidefs.h" #include "../includes/iguana_apideclares.h" #include "../includes/iguana_apideclares2.h" TWO_STRINGS(tradebot,gensvm,base,rel) { #ifdef _WIN return(clonestr("{\"error\":\"windows doesnt support SVM\"}")); #else int32_t numfeatures = 317*61; struct tradebot_arbpair *pair; if ( base[0] != 0 && rel[0] != 0 && (pair= tradebots_arbpair_find(base,rel)) != 0 && pair->fp != 0 ) { tradebots_calcanswers(pair); ocas_gen(pair->refc,numfeatures,0,(int32_t)(ftell(pair->fp) / sizeof(pair->rawfeatures))); return(clonestr("{\"result\":\"success\"}")); } else return(clonestr("{\"error\":\"cant find arbpair\"}")); #endif } ZERO_ARGS(tradebot,openliquidity) { int32_t i; cJSON *array = cJSON_CreateArray(); for (i=0; ilinfos)/sizeof(*myinfo->linfos); i++) { if ( myinfo->linfos[i].base[0] != 0 ) jaddi(array,linfo_json(&myinfo->linfos[i])); } return(jprint(array,1)); } ZERO_ARGS(tradebot,allbalances) { int32_t i,n; double value,pending; char *base; cJSON *item,*balances = cJSON_CreateObject(); if ( myinfo->liquidity_currencies == 0 ) myinfo->liquidity_currencies = cJSON_Parse("[\"KMD\", \"BTC\"]"); if ( myinfo->liquidity_currencies != 0 && (n= cJSON_GetArraySize(myinfo->liquidity_currencies)) > 0 ) { for (i=0; iliquidity_currencies,i); value = tradebot_balance(myinfo,base); pending = tradebot_pending(myinfo,base); item = cJSON_CreateObject(); jaddnum(item,"value",value); jaddnum(item,"pending",pending); jadd(balances,base,item); } } return(jprint(balances,1)); } ZERO_ARGS(tradebot,anchor) { FILE *fp; char *anchorstr,fname[512]; cJSON *anchor; int32_t retval = -1; if ( (anchorstr= tradebot_allbalances(myinfo,0,0,0)) != 0 ) { if ( (anchor= cJSON_Parse(anchorstr)) != 0 ) { if ( jobj(anchor,"error") == 0 ) { sprintf(fname,"%s/anchor",GLOBAL_DBDIR), OS_compatible_path(fname); if ( (fp= fopen(fname,"wb")) != 0 ) { if ( fwrite(anchorstr,1,strlen(anchorstr)+1,fp) == strlen(anchorstr)+1 ) retval = 0; fclose(fp); } } } free(anchorstr); } if ( retval == 0 ) return(clonestr("{\"result\":\"success\"}")); else return(clonestr("{\"error\":\"couldnt make anchor file\"}")); } ZERO_ARGS(tradebot,portfolio) { char *currentstr,*anchorstr,fname[512]; long fsize; cJSON *current,*anchor=0,*portfolio=0; if ( (currentstr= tradebot_allbalances(myinfo,0,0,0)) != 0 ) { if ( (current= cJSON_Parse(currentstr)) != 0 ) { sprintf(fname,"%s/anchor",GLOBAL_DBDIR), OS_compatible_path(fname); if ( (anchorstr= OS_filestr(&fsize,fname)) != 0 ) { anchor = cJSON_Parse(anchorstr); free(anchorstr); } if ( anchor == 0 ) anchor = cJSON_Parse("{}"); portfolio = tradebot_balancesdiff(myinfo,current,anchor); free_json(current); } free(currentstr); } if ( portfolio == 0 ) return(clonestr("{\"result\":\"success\"}")); else return(jprint(portfolio,1)); } ARRAY_OBJ_INT(tradebot,goals,currencies,vals,targettime) { static bits256 zero; char *targetcoin; int32_t i,n; if ( currencies != 0 && vals != 0 ) { // init things so automatically updates refli.bid and refli.ask // volume range with margin // currency percentage value in BTC? target distribution, max percentage, min percentage` // min price to sell, max price to buy, max volume n = cJSON_GetArraySize(currencies); for (i=0; imyaddr.persistent); if ( (msgid= juint(vals,"msgid")) == 0 ) { msgid = (uint32_t)time(NULL); jdelete(vals,"msgid"); jaddnum(vals,"msgid",msgid); } if ( myinfo->NOTARY.RELAYID >= 0 || myinfo->dexsock >= 0 || myinfo->subsock >= 0 ) { channel = juint(vals,"channel"); width = juint(vals,"width"); retstr = basilisk_iterate_MSG(myinfo,channel,msgid,jbits256(vals,"srchash"),jbits256(vals,"desthash"),width); //printf("getmessage.(%s)\n",retstr); return(retstr); } //printf("getmessage not relay.%d dexsock.%d subsock.%d\n",myinfo->NOTARY.RELAYID,myinfo->dexsock,myinfo->subsock); return(basilisk_standardservice("MSG",myinfo,0,jbits256(vals,"desthash"),vals,hexstr,1)); } HASH_ARRAY_STRING(basilisk,sendmessage,hash,vals,hexstr) { int32_t keylen,datalen,allocsize = 65536; uint8_t key[BASILISK_KEYSIZE],*space,*space2,*data,*ptr = 0; char *retstr=0; space = calloc(1,allocsize); space2 = calloc(1,allocsize); data = get_dataptr(BASILISK_HDROFFSET,&ptr,&datalen,&space[BASILISK_KEYSIZE],allocsize-BASILISK_KEYSIZE,hexstr); if ( myinfo->subsock >= 0 || myinfo->dexsock >= 0 || (myinfo->IAMNOTARY != 0 && myinfo->NOTARY.RELAYID >= 0) ) { keylen = basilisk_messagekey(key,juint(vals,"channel"),juint(vals,"msgid"),jbits256(vals,"srchash"),jbits256(vals,"desthash")); if ( data != 0 ) { retstr = basilisk_respond_addmessage(myinfo,key,keylen,data,datalen,0,juint(vals,"duration")); } else printf("no get_dataptr\n"); if ( retstr != 0 ) free(retstr); } //else printf("not notary.%d relayid.%d\n",myinfo->IAMNOTARY,myinfo->NOTARY.RELAYID); if ( vals != 0 && juint(vals,"fanout") == 0 ) jaddnum(vals,"fanout",MAX(8,(int32_t)sqrt(myinfo->NOTARY.NUMRELAYS)+2)); if ( BASILISK_KEYSIZE+datalen < allocsize ) { memcpy(space2,key,BASILISK_KEYSIZE); if ( data != 0 && datalen != 0 ) memcpy(&space2[BASILISK_KEYSIZE],data,datalen); dex_reqsend(myinfo,"DEX",space2,datalen+BASILISK_KEYSIZE,1,""); } else printf("sendmessage space too small error for %d\n",datalen); free(space); free(space2); if ( ptr != 0 ) free(ptr); return(basilisk_standardservice("OUT",myinfo,0,jbits256(vals,"desthash"),vals,hexstr,0)); } HASH_ARRAY_STRING(basilisk,value,hash,vals,hexstr) { char *retstr=0,*symbol,*coinaddr,*infostr; cJSON *retjson,*sobj,*info,*addrs,*txoutjson,*txjson,*array; uint32_t basilisktag,blocktime,numtx=0; bits256 txid,blockhash,merkleroot; struct basilisk_item *ptr,Lptr; uint64_t value; int32_t timeoutmillis,vout,height,n,m; if ( vals == 0 ) return(clonestr("{\"error\":\"null valsobj\"}")); //if ( myinfo->IAMNOTARY != 0 || myinfo->NOTARY.RELAYID >= 0 ) // return(clonestr("{\"error\":\"special relays only do OUT and MSG\"}")); //if ( coin == 0 ) { if ( (symbol= jstr(vals,"symbol")) != 0 || (symbol= jstr(vals,"coin")) != 0 ) coin = iguana_coinfind(symbol); } if ( jobj(vals,"fanout") == 0 ) jaddnum(vals,"fanout",MAX(5,(int32_t)sqrt(myinfo->NOTARY.NUMRELAYS)+1)); txid = jbits256(vals,"txid"); vout = jint(vals,"vout"); if ( coin != 0 ) { if ( coin->FULLNODE < 0 ) { if ( (txoutjson= dpow_gettxout(myinfo,coin,txid,vout)) != 0 ) { if ( (value= SATOSHIDEN*jdouble(txoutjson,"value")) == 0 ) value = SATOSHIDEN*jdouble(txoutjson,"amount"); if ( (coinaddr= jstr(txoutjson,"address")) == 0 ) { if ( (sobj= jobj(txoutjson,"scriptPubKey")) != 0 && (addrs= jarray(&n,sobj,"addresses")) != 0 && n > 0 ) coinaddr = jstri(addrs,0); printf("no address, check addrs %p coinaddr.%p\n",sobj,coinaddr); } if ( coinaddr != 0 && value != 0 ) { retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jaddstr(retjson,"address",coinaddr); jadd64bits(retjson,"satoshis",value); jaddnum(retjson,"value",dstr(value)); jaddnum(retjson,"amount",dstr(value)); height = dpow_getchaintip(myinfo,&merkleroot,&blockhash,&blocktime,0,&numtx,coin); jaddnum(retjson,"height",height); jaddnum(retjson,"numconfirms",jint(txoutjson,"confirmations")); jaddbits256(retjson,"txid",txid); jaddnum(retjson,"vout",vout); jaddstr(retjson,"coin",coin->symbol); } else { printf("missing fields.(%s)\n",jprint(txoutjson,0)); free_json(txoutjson); return(clonestr("{\"error\":\"return from gettxout missing fields\"}")); } free_json(txoutjson); return(jprint(retjson,1)); } //else return(clonestr("{\"error\":\"null return from gettxout\"}")); } else { if ( (basilisktag= juint(vals,"basilisktag")) == 0 ) basilisktag = rand(); if ( (timeoutmillis= juint(vals,"timeout")) <= 0 ) timeoutmillis = BASILISK_TIMEOUT; if ( coin->FULLNODE > 0 && (ptr= basilisk_bitcoinvalue(&Lptr,myinfo,coin,remoteaddr,basilisktag,timeoutmillis,vals)) != 0 ) { retstr = ptr->retstr, ptr->retstr = 0; ptr->finished = OS_milliseconds() + 10000; return(retstr); } } } if ( myinfo->reqsock >= 0 ) { if ( (retstr= _dex_getrawtransaction(myinfo,symbol,txid)) != 0 ) { if ( (txoutjson= cJSON_Parse(retstr)) != 0 ) { //printf("TX.(%s)\n",jprint(txoutjson,0)); retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jaddnum(retjson,"numconfirms",jint(txoutjson,"confirmations")); if ( (height= jint(txoutjson,"height")) == 0 && coin != 0 ) height = coin->longestchain - jint(txoutjson,"confirmations"); jaddnum(retjson,"height",height); if ( (array= jarray(&n,txoutjson,"vout")) != 0 && vout < n && (txjson= jitem(array,vout)) != 0 ) { //printf("txjson.(%s)\n",jprint(txjson,0)); if ( (value= jdouble(txjson,"value") * SATOSHIDEN) != 0 ) { if ( (sobj= jobj(txjson,"scriptPubKey")) != 0 && (addrs= jarray(&m,sobj,"addresses")) != 0 && (coinaddr= jstri(addrs,0)) != 0 ) jaddstr(retjson,"address",coinaddr); jadd64bits(retjson,"satoshis",value); jaddnum(retjson,"value",dstr(value)); if ( (infostr= _dex_getinfo(myinfo,symbol)) != 0 ) { if ( (info= cJSON_Parse(infostr)) != 0 ) { if ( (height= jint(info,"blocks")) > 0 ) { height -= jint(txoutjson,"confirmations"); jaddnum(retjson,"height",height); } free_json(info); } free(infostr); } jaddbits256(retjson,"txid",txid); jaddnum(retjson,"vout",vout); jaddstr(retjson,"coin",symbol); free(retstr); free_json(txoutjson); return(jprint(retjson,1)); } } free_json(txoutjson); return(jprint(retjson,1)); } return(retstr); } } return(basilisk_standardservice("VAL",myinfo,0,hash,vals,hexstr,1)); } HASH_ARRAY_STRING(basilisk,rawtx,hash,vals,hexstr) { char *retstr=0,*symbol; uint32_t basilisktag; int32_t timeoutmillis,i,retval = -1; uint64_t amount,txfee; cJSON *retarray; if ( vals == 0 ) return(clonestr("{\"error\":\"null valsobj\"}")); //if ( coin == 0 ) { if ( (symbol= jstr(vals,"symbol")) != 0 || (symbol= jstr(vals,"coin")) != 0 ) coin = iguana_coinfind(symbol); } if ( jobj(vals,"numrequired") == 0 ) jaddnum(vals,"numrequired",MIN(3,(int32_t)sqrt(myinfo->NOTARY.NUMRELAYS)+1)); if ( jobj(vals,"fanout") == 0 ) jaddnum(vals,"fanout",MAX(3,(int32_t)sqrt(myinfo->NOTARY.NUMRELAYS)+1)); if ( coin != 0 ) { //if ( juint(vals,"burn") == 0 ) // jaddnum(vals,"burn",0.0001); if ( (basilisktag= juint(vals,"basilisktag")) == 0 ) basilisktag = rand(); if ( (timeoutmillis= juint(vals,"timeout")) <= 0 ) timeoutmillis = BASILISK_TIMEOUT; if ( (retstr= basilisk_bitcoinrawtx(myinfo,coin,remoteaddr,basilisktag,timeoutmillis,vals,0)) != 0 ) { printf("rawtx.(%s)\n",retstr); if ( (amount= j64bits(vals,"satoshis")) == 0 ) amount = jdouble(vals,"value") * SATOSHIDEN; if ( (txfee= j64bits(vals,"txfee")) == 0 ) txfee = coin->chain->txfee; if ( txfee == 0 ) txfee = 10000; retval = -1; if ( (retarray= cJSON_Parse(retstr)) != 0 ) { if ( is_cJSON_Array(retarray) != 0 ) { for (i=0; iFULLNODE >= 0 ) return(clonestr("{\"error\":\"no passphrase or no native komodod\"}")); else { safecopy(myinfo->jumblr_passphrase,passphrase,sizeof(myinfo->jumblr_passphrase)); retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); smartaddress_add(myinfo,privkey,"deposit","KMD",0.,0.); myinfo->jumblr_depositkey = curve25519(privkey,curve25519_basepoint9()); bitcoin_priv2wif(wifstr,privkey,coin->chain->wiftype); if ( coin->FULLNODE < 0 ) jumblr_importprivkey(myinfo,coin,wifstr); jaddstr(retjson,"KMDdeposit",KMDaddr); jaddstr(retjson,"BTCdeposit",BTCaddr); if ( (coinbtc= iguana_coinfind("BTC")) != 0 ) { bitcoin_priv2wif(wifstr,privkey,coinbtc->chain->wiftype); if ( coinbtc->FULLNODE < 0 ) jumblr_importprivkey(myinfo,coinbtc,wifstr); jaddnum(retjson,"BTCdeposits",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); } privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); smartaddress_add(myinfo,privkey,"jumblr","KMD",0.,0.); myinfo->jumblr_pubkey = curve25519(privkey,curve25519_basepoint9()); jaddstr(retjson,"KMDjumblr",KMDaddr); jaddstr(retjson,"BTCjumblr",BTCaddr); if ( coinbtc != 0 ) jaddnum(retjson,"BTCjumbled",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); if ( (smartaddrs= InstantDEX_smartaddresses(myinfo,0,0,0)) != 0 ) { if ( (tmp= cJSON_Parse(smartaddrs)) != 0 ) jadd(retjson,"smartaddresses",tmp); free(smartaddrs); } return(jprint(retjson,1)); } } ZERO_ARGS(jumblr,runsilent) { myinfo->runsilent = 1; return(clonestr("{\"result\":\"success\",\"mode\":\"runsilent\"}")); } ZERO_ARGS(jumblr,totransparent) { myinfo->runsilent = 0; return(clonestr("{\"result\":\"success\",\"mode\":\"totransparent\"}")); } ZERO_ARGS(jumblr,status) { cJSON *retjson; char KMDaddr[64],BTCaddr[64]; struct jumblr_item *ptr,*tmp; struct iguana_info *coinbtc; int64_t received,deposited,jumblred,step_t2z,step_z2z,step_z2t,finished,pending,maxval,minval; if ( strcmp(coin->symbol,"KMD") == 0 && coin->FULLNODE < 0 && myinfo->jumblr_passphrase[0] != 0 ) { jumblr_opidsupdate(myinfo,coin); retjson = cJSON_CreateObject(); step_t2z = step_z2z = step_z2t = deposited = finished = pending = 0; jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,JUMBLR_DEPOSITPREFIX); jaddstr(retjson,"mode",myinfo->runsilent == 0 ? "totransparent" : "runsilent"); jaddstr(retjson,"KMDdeposit",KMDaddr); jaddstr(retjson,"BTCdeposit",BTCaddr); if ( (coinbtc= iguana_coinfind("BTC")) != 0 ) jaddnum(retjson,"BTCdeposits",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); received = jumblr_receivedby(myinfo,coin,KMDaddr); deposited = jumblr_balance(myinfo,coin,KMDaddr); jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,""); jaddstr(retjson,"KMDjumblr",KMDaddr); jaddstr(retjson,"BTCjumblr",BTCaddr); if ( coinbtc != 0 ) jaddnum(retjson,"BTCjumbled",dstr(jumblr_balance(myinfo,coinbtc,BTCaddr))); finished = jumblr_receivedby(myinfo,coin,KMDaddr); jumblred = jumblr_balance(myinfo,coin,KMDaddr); HASH_ITER(hh,myinfo->jumblrs,ptr,tmp) { if ( strlen(ptr->src) >= 40 ) { if ( strlen(ptr->dest) >= 40 ) step_z2z += ptr->amount; else step_z2t += ptr->amount; } else step_t2z += ptr->amount; } jaddstr(retjson,"result","success"); jaddnum(retjson,"deposits",dstr(deposited)); jaddnum(retjson,"t_to_z",dstr(step_t2z)); jaddnum(retjson,"z_to_z",dstr(step_z2z)); jaddnum(retjson,"z_to_t",dstr(step_z2t)); maxval = MAX(step_t2z,MAX(step_z2z,step_z2t)); minval = MIN(step_t2z,MIN(step_z2z,step_z2t)); if ( maxval > minval ) { pending = (maxval - minval); if ( pending < finished*.1 ) pending = 0; } jaddnum(retjson,"pending",dstr(pending)); jaddnum(retjson,"jumbled",dstr(jumblred)); jaddnum(retjson,"received",dstr(received)); jaddnum(retjson,"finished",dstr(finished)); return(jprint(retjson,1)); } else { printf("(%s) (%s) %d\n",coin->symbol,myinfo->jumblr_passphrase,coin->FULLNODE); return(clonestr("{\"error\":\"jumblr status no passphrase or no native komodod\"}")); } } HASH_ARRAY_STRING(basilisk,balances,hash,vals,hexstr) { char *retstr=0,*symbol; uint32_t basilisktag; struct basilisk_item *ptr,Lptr; int32_t timeoutmillis; if ( myinfo->NOTARY.RELAYID >= 0 ) return(clonestr("{\"error\":\"special relays only do OUT and MSG\"}")); if ( vals == 0 ) return(clonestr("{\"error\":\"need vals object\"}")); if ( (symbol= jstr(vals,"symbol")) != 0 || (symbol= jstr(vals,"coin")) != 0 ) coin = iguana_coinfind(symbol); if ( jobj(vals,"history") == 0 ) jaddnum(vals,"history",3); if ( jobj(vals,"fanout") == 0 ) jaddnum(vals,"fanout",MAX(8,(int32_t)sqrt(myinfo->NOTARY.NUMRELAYS)+1)); if ( jobj(vals,"numrequired") == 0 ) jaddnum(vals,"numrequired",MIN(juint(vals,"fanout")/2,(int32_t)sqrt(myinfo->NOTARY.NUMRELAYS))); if ( jobj(vals,"addresses") == 0 ) { jadd(vals,"addresses",iguana_getaddressesbyaccount(myinfo,coin,"*")); //printf("added all %s addresses: %s\n",coin->symbol,jprint(vals,0)); } //else printf("have addresses.(%s)\n",jprint(jobj(vals,"addresses"),0)); if ( (basilisktag= juint(vals,"basilisktag")) == 0 ) basilisktag = rand(); if ( (timeoutmillis= juint(vals,"timeout")) <= 0 ) timeoutmillis = BASILISK_TIMEOUT; if ( coin != 0 ) { if ( coin->FULLNODE > 0 || coin->VALIDATENODE > 0 || coin->notarychain >= 0 ) { if ( (ptr= basilisk_bitcoinbalances(&Lptr,myinfo,coin,remoteaddr,basilisktag,timeoutmillis,vals)) != 0 ) { retstr = ptr->retstr, ptr->retstr = 0; ptr->finished = OS_milliseconds() + 10000; return(retstr); } return(clonestr("{\"error\":\"no result\"}")); } } else printf("no coin\n"); if ( (retstr= basilisk_standardservice("BAL",myinfo,0,hash,vals,hexstr,1)) != 0 ) { basilisk_unspents_process(myinfo,coin,retstr); } return(retstr); } HASH_ARRAY_STRING(basilisk,history,hash,vals,hexstr) { int64_t total = 0; int32_t i,n; char *symbol; cJSON *retjson,*unspents,*spends,*array; //struct basilisk_spend *s; struct basilisk_unspent *bu; int32_t i; struct iguana_waccount *wacct,*tmp; struct iguana_waddress *waddr,*tmp2; if ( vals == 0 ) return(clonestr("{\"error\":\"need vals object\"}")); //if ( coin == 0 ) { if ( (symbol= jstr(vals,"symbol")) != 0 || (symbol= jstr(vals,"coin")) != 0 ) coin = iguana_coinfind(symbol); } if ( coin == 0 ) return(clonestr("{\"error\":\"couldnt find coin\"}")); unspents = cJSON_CreateArray(); spends = cJSON_CreateArray(); portable_mutex_lock(&myinfo->bu_mutex); //HASH_ITER(hh,myinfo->wallet,wacct,tmp) { //HASH_ITER(hh,wacct->waddr,waddr,tmp2) { if ( myinfo->Cunspents != 0 ) { //printf("Cunspents.(%s)\n",jprint(waddr->Cunspents,0)); if ( (array= jobj(myinfo->Cunspents,coin->symbol)) != 0 ) { if ( (n= cJSON_GetArraySize(array)) > 0 ) { for (i=0; iCspends != 0 ) { //printf("Cspends.(%s)\n",jprint(waddr->Cspends,0)); if ( (array= jobj(myinfo->Cspends,coin->symbol)) != 0 ) jaddi(spends,jduplicate(array)); } } } portable_mutex_unlock(&myinfo->bu_mutex); retjson = cJSON_CreateObject(); jaddstr(retjson,"result","success"); jadd(retjson,"unspents",unspents); jadd(retjson,"spends",spends); jaddstr(retjson,"coin",coin->symbol); jaddnum(retjson,"balance",dstr(total)); //printf("return history balance %s %.8f\n",coin->symbol,dstr(total)); return(jprint(retjson,1)); } INT_ARG(passthru,paxfiats,mask) { if ( mask == 0 ) mask = -1; komodo_assetcoins(-1,mask); return(clonestr("{\"result\":\"success\"}")); } INT_ARG(basilisk,paxfiats,mask) { if ( mask == 0 ) mask = -1; komodo_assetcoins(0,mask); return(clonestr("{\"result\":\"success\"}")); } INT_ARG(iguana,paxfiats,mask) { if ( mask == 0 ) mask = -1; komodo_assetcoins(1,mask); return(clonestr("{\"result\":\"success\"}")); } int32_t utxocmp(cJSON *utxo,cJSON *utxo2) { bits256 txid,txid2; int32_t vout=-1,vout2=-1; //printf("cmp (%s) vs (%s)\n",jprint(utxo,0),jprint(utxo2,0)); txid = jbits256(utxo,"txid"); vout = jint(utxo,"vout"); txid2 = jbits256(utxo2,"txid"); vout2 = jint(utxo2,"vout"); if ( bits256_cmp(txid,txid2) == 0 && vout == vout2 ) return(0); else return(-1); } ZERO_ARGS(basilisk,cancelrefresh) { myinfo->cancelrefresh = 1; return(clonestr("{\"result\":\"refresh cancel started\"}")); } TWO_STRINGS(basilisk,refresh,symbol,address) { cJSON *array=0,*array2=0,*array3,*item,*item2; char *retstr; int32_t i,j,n,m,vout; bits256 txid; myinfo->cancelrefresh = 0; if ( symbol != 0 && iguana_isnotarychain(symbol) >= 0 && address != 0 && address[0] != 0 ) { if ( (retstr= _dex_listunspent(myinfo,symbol,address)) != 0 ) { array = cJSON_Parse(retstr); free(retstr); } if ( (retstr= _dex_listunspent2(myinfo,symbol,address)) != 0 ) { if ( array == 0 ) array = cJSON_Parse(retstr); else array2 = cJSON_Parse(retstr); free(retstr); } if ( array != 0 && array2 != 0 ) // merge { m = cJSON_GetArraySize(array2); array3 = jduplicate(array); n = cJSON_GetArraySize(array3); //printf("MERGE %s and %s\n",jprint(array,0),jprint(array2,0)); for (j=0; jcancelrefresh != 0 ) break; item2 = jitem(array2,j); for (i=0; icancelrefresh != 0 ) break; item = jitem(array,i); txid = jbits256(item,"txid"); vout = jint(item,"vout"); if ( (retstr= _dex_gettxout(myinfo,symbol,txid,vout)) != 0 ) { if ( (item2= cJSON_Parse(retstr)) != 0 ) { if ( jdouble(item2,"value") > 0 ) { jaddbits256(item2,"txid",txid); jaddnum(item2,"vout",vout); jaddnum(item2,"amount",jdouble(item2,"value")); //printf("%s\n",jprint(item2,0)); jaddi(array3,item2); } else free_json(item2); } free(retstr); } } free_json(array); myinfo->cancelrefresh = 0; return(jprint(array3,1)); } else return(clonestr("[]")); } myinfo->cancelrefresh = 0; return(clonestr("{\"error\":\"invalid coin or address specified\"}")); } STRING_ARRAY_OBJ_STRING(basilisk,utxorawtx,symbol,utxos,vals,ignore) { char *destaddr,*changeaddr; int64_t satoshis,txfee; int32_t completed,sendflag,timelock; timelock = jint(vals,"timelock"); sendflag = jint(vals,"sendflag"); satoshis = jdouble(vals,"amount") * SATOSHIDEN; destaddr = jstr(vals,"destaddr"); changeaddr = jstr(vals,"changeaddr"); if ( destaddr != 0 && changeaddr != 0 && symbol != 0 && (coin= iguana_coinfind(symbol)) != 0 ) { txfee = jdouble(vals,"txfee") * SATOSHIDEN; return(iguana_utxorawtx(myinfo,coin,timelock,destaddr,changeaddr,&satoshis,1,txfee,&completed,sendflag,utxos,0)); } return(clonestr("{\"error\":\"invalid coin or address specified\"}")); } HASH_ARRAY_STRING(basilisk,utxocombine,ignore,vals,symbol) { char *coinaddr,*retstr=0; cJSON *utxos; int64_t satoshis,limit,txfee; int32_t maxvins,completed,sendflag,timelock; timelock = 0; if ( (maxvins= jint(vals,"maxvins")) == 0 ) maxvins = 20; sendflag = jint(vals,"sendflag"); coinaddr = jstr(vals,"coinaddr"); limit = jdouble(vals,"maxamount") * SATOSHIDEN; if ( limit > 0 && symbol != 0 && symbol[0] != 0 && (utxos= basilisk_utxosweep(myinfo,symbol,&satoshis,limit,maxvins,coinaddr)) != 0 && cJSON_GetArraySize(utxos) > 0 ) { if ( coinaddr != 0 && symbol != 0 && (coin= iguana_coinfind(symbol)) != 0 ) { txfee = jdouble(vals,"txfee") * SATOSHIDEN; retstr = iguana_utxorawtx(myinfo,coin,timelock,coinaddr,coinaddr,&satoshis,1,txfee,&completed,sendflag,utxos,0); } free_json(utxos); } if ( retstr == 0 ) return(clonestr("{\"error\":\"invalid coin or address specified or no available utxos\"}")); return(retstr); } //int64_t iguana_verifytimelock(struct supernet_info *myinfo,struct iguana_info *coin,uint32_t timelocked,char *destaddr,bits256 txid,int32_t vout) 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)); } ZERO_ARGS(InstantDEX,allcoins) { struct iguana_info *tmp; cJSON *native,*notarychains,*basilisk,*virtual,*full,*retjson = cJSON_CreateObject(); full = cJSON_CreateArray(); native = cJSON_CreateArray(); basilisk = cJSON_CreateArray(); virtual = cJSON_CreateArray(); notarychains = cJSON_CreateArray(); HASH_ITER(hh,myinfo->allcoins,coin,tmp) { if ( coin->FULLNODE < 0 ) jaddistr(native,coin->symbol); //else if ( coin->virtualchain != 0 ) // jaddistr(virtual,coin->symbol); else if ( coin->FULLNODE > 0 )//|| coin->VALIDATENODE > 0 ) jaddistr(full,coin->symbol); //else if ( coin->notarychain >= 0 ) // jaddistr(notarychains,coin->symbol); else jaddistr(basilisk,coin->symbol); } jadd(retjson,"native",native); jadd(retjson,"basilisk",basilisk); jadd(retjson,"full",full); //jadd(retjson,"virtual",virtual); //jadd(retjson,"notarychains",notarychains); return(jprint(retjson,1)); } STRING_ARG(InstantDEX,available,source) { uint64_t total = 0; int32_t i,n=0; char coinaddr[64]; cJSON *item,*unspents,*retjson = 0; if ( source != 0 && source[0] != 0 && (coin= iguana_coinfind(source)) != 0 ) { if ( myinfo->expiration != 0 ) { bitcoin_address(coinaddr,coin->chain->pubtype,myinfo->persistent_pubkey33,33); if ( (unspents= basilisk_unspents(myinfo,coin,coinaddr)) != 0 ) { //printf("available.(%s)\n",jprint(unspents,0)); if ( (n= cJSON_GetArraySize(unspents)) > 0 ) { for (i=0; i %.8f\n",jprint(item,0),dstr(total)); } } free_json(unspents); } retjson = cJSON_CreateObject(); jaddnum(retjson,"result",dstr(total)); printf(" n.%d total %.8f (%s)\n",n,dstr(total),jprint(retjson,0)); return(jprint(retjson,1)); } printf("InstantDEX_available: need to unlock wallet\n"); return(clonestr("{\"error\":\"need to unlock wallet\"}")); } printf("InstantDEX_available: %s is not active\n",source!=0?source:""); return(clonestr("{\"error\":\"specified coin is not active\"}")); } HASH_ARRAY_STRING(InstantDEX,request,hash,vals,hexstr) { uint8_t serialized[512]; bits256 privkey; char buf[512],BTCaddr[64],KMDaddr[64]; struct basilisk_request R; int32_t jumblr,iambob,optionhours; cJSON *reqjson; uint32_t datalen=0,DEX_channel; struct iguana_info *bobcoin,*alicecoin; myinfo->DEXactive = (uint32_t)time(NULL) + 3*BASILISK_TIMEOUT + 60; jadd64bits(vals,"minamount",jdouble(vals,"minprice") * jdouble(vals,"amount") * SATOSHIDEN); if ( jobj(vals,"desthash") == 0 ) jaddbits256(vals,"desthash",hash); jadd64bits(vals,"satoshis",jdouble(vals,"amount") * SATOSHIDEN); jadd64bits(vals,"destsatoshis",jdouble(vals,"destamount") * SATOSHIDEN); jaddnum(vals,"timestamp",time(NULL)); if ( (jumblr= jint(vals,"usejumblr")) != 0 ) privkey = jumblr_privkey(myinfo,BTCaddr,0,KMDaddr,jumblr == 1 ? JUMBLR_DEPOSITPREFIX : ""); else privkey = myinfo->persistent_priv; hash = curve25519(privkey,curve25519_basepoint9()); if ( jobj(vals,"srchash") == 0 ) jaddbits256(vals,"srchash",hash); printf("service.(%s)\n",jprint(vals,0)); memset(&R,0,sizeof(R)); if ( basilisk_request_create(&R,vals,hash,juint(vals,"timestamp"),juint(vals,"DEXselector")) == 0 ) { iambob = bitcoin_coinptrs(hash,&bobcoin,&alicecoin,R.src,R.dest,privkey,GENESIS_PUBKEY); if ( (optionhours= jint(vals,"optionhours")) != 0 ) { printf("iambob.%d optionhours.%d R.requestid.%u vs calc %u, q.%u\n",iambob,R.optionhours,R.requestid,basilisk_requestid(&R),R.quoteid); if ( iambob != 0 && optionhours > 0 ) { sprintf(buf,"{\"error\":\"illegal call option request hours.%d when iambob.%d\"}",optionhours,iambob); printf("ERROR.(%s)\n",buf); return(clonestr(buf)); } else if ( iambob == 0 && optionhours < 0 ) { sprintf(buf,"{\"error\":\"illegal put option request hours.%d when iambob.%d\"}",optionhours,iambob); printf("ERROR.(%s)\n",buf); return(clonestr(buf)); } } //if ( myinfo->IAMNOTARY != 0 || myinfo->NOTARY.RELAYID >= 0 ) // R.relaybits = myinfo->myaddr.myipbits; if ( (reqjson= basilisk_requestjson(&R)) != 0 ) free_json(reqjson); datalen = basilisk_rwDEXquote(1,serialized,&R); //int32_t i; for (i=0; i 0 ) { uint32_t msgid;//,crc=0,crcs[2],numiters = 0; uint8_t buf[4096]; memset(hash.bytes,0,sizeof(hash)); msgid = (uint32_t)time(NULL); DEX_channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); myinfo->DEXtrades++; // not exact but allows a one side initiated self-trade basilisk_channelsend(myinfo,hash,hash,DEX_channel,msgid,serialized,datalen,60); sleep(3); /*while ( numiters < 10 && (crc= basilisk_crcsend(myinfo,0,buf,sizeof(buf),hash,myinfo->myaddr.persistent,DEX_channel,msgid,serialized,datalen,crcs)) == 0 ) { //printf("didnt get back what was sent\n"); sleep(3); basilisk_channelsend(myinfo,myinfo->myaddr.persistent,hash,DEX_channel,msgid,serialized,datalen,60); numiters++; }*/ //if ( crc != 0 )//basilisk_channelsend(myinfo,R.srchash,R.desthash,DEX_channel,(uint32_t)time(NULL),serialized,datalen,30) == 0 ) return(clonestr("{\"result\":\"DEX message sent\"}")); //else return(clonestr("{\"error\":\"DEX message couldnt be sent\"}")); } return(clonestr("{\"error\":\"DEX message not sent\"}")); } INT_ARG(InstantDEX,automatched,requestid) { // return quoteid myinfo->DEXactive = (uint32_t)time(NULL) + INSTANTDEX_LOCKTIME; return(clonestr("{\"result\":\"automatched not yet\"}")); } int32_t InstantDEX_incoming_func(struct supernet_info *myinfo,void *ptr,uint8_t *data,int32_t datalen) { //int32_t i; //for (i=0; inumsmartaddrs+1; int32_t retval,width,drift=3; bits256 pubkey; uint8_t data[32768]; now = (uint32_t)time(NULL); memset(&zero,0,sizeof(zero)); width = (now - myinfo->DEXpoll) + 2*drift; if ( width < (drift+1) ) width = 2*drift+1; else if ( width > 64 ) width = 64; if ( (counter % n) == n-1 ) pubkey = myinfo->myaddr.persistent; else pubkey = myinfo->smartaddrs[counter % n].pubkey; counter++; myinfo->DEXpoll = now; retjson = cJSON_CreateObject(); DEX_channel = 'D' + ((uint32_t)'E' << 8) + ((uint32_t)'X' << 16); msgid = (uint32_t)time(NULL) + drift; if ( (retarray= basilisk_channelget(myinfo,zero,pubkey,DEX_channel,msgid,width)) != 0 ) { //printf("GOT.(%s)\n",jprint(retarray,0)); if ( (retval= basilisk_process_retarray(myinfo,0,InstantDEX_process_channelget,data,sizeof(data),DEX_channel,msgid,retarray,InstantDEX_incoming_func)) > 0 ) { jaddstr(retjson,"result","success"); } else jaddstr(retjson,"error","cant process InstantDEX retarray"); jadd(retjson,"responses",retarray); } else { jaddstr(retjson,"error","cant do InstantDEX channelget"); //char str[65]; printf("error channelget %s %x\n",bits256_str(str,pubkey),msgid); } return(jprint(retjson,1)); } /*TWO_INTS(InstantDEX,swapstatus,requestid,quoteid) { cJSON *vals; char *retstr; myinfo->DEXactive = (uint32_t)time(NULL) + INSTANTDEX_LOCKTIME; //if ( myinfo->IAMLP != 0 ) // return(basilisk_respond_swapstatus(myinfo,myinfo->myaddr.persistent,requestid,quoteid)); //else { vals = cJSON_CreateObject(); jaddnum(vals,"requestid",(uint32_t)requestid); jaddnum(vals,"quoteid",(uint32_t)quoteid); jaddbits256(vals,"hash",myinfo->myaddr.persistent); retstr = basilisk_standardservice("SWP",myinfo,0,myinfo->myaddr.persistent,vals,"",1); free_json(vals); return(retstr); } }*/ TWO_INTS(InstantDEX,accept,requestid,quoteid) { cJSON *vals; char *retstr; myinfo->DEXactive = (uint32_t)time(NULL) + INSTANTDEX_LOCKTIME; if ( myinfo->IAMLP != 0 || myinfo->dexsock >= 0 || myinfo->subsock >= 0 ) return(basilisk_respond_accept(myinfo,myinfo->persistent_priv,requestid,quoteid,&myinfo->DEXaccept)); else { vals = cJSON_CreateObject(); jaddnum(vals,"quoteid",(uint32_t)quoteid); jaddnum(vals,"requestid",(uint32_t)requestid); retstr = basilisk_standardservice("ACC",myinfo,0,myinfo->myaddr.persistent,vals,"",1); free_json(vals); return(retstr); } } ZERO_ARGS(InstantDEX,init) { basilisk_swaps_init(myinfo); return(clonestr("{\"result\":\"success\"}")); } ZERO_ARGS(InstantDEX,getswaplist) { return(basilisk_swaplist(myinfo)); } DOUBLE_ARG(InstantDEX,DEXratio,ratio) { if ( ratio < 0.95 || ratio > 1.01 ) return(clonestr("{\"result\":\"error\",\"description\":\"DEXratio must be between 0.95 and 1.01\"}")); myinfo->DEXratio = ratio; return(clonestr("{\"result\":\"success\"}")); } #include "../includes/iguana_apiundefs.h"