Browse Source

serialize OUT/MSG

dPoW2
jl777 8 years ago
parent
commit
c3a67a5e8f
  1. 153
      basilisk/basilisk.c
  2. 2
      basilisk/basilisk.h
  3. 43
      basilisk/basilisk_MSG.c
  4. 8
      basilisk/basilisk_ping.c
  5. 2
      iguana/iguana777.h
  6. 2
      iguana/iguana_msg.c
  7. 8
      includes/iguana_structs.h

153
basilisk/basilisk.c

@ -769,9 +769,48 @@ void basilisk_msgprocess(struct supernet_info *myinfo,void *_addr,uint32_t sende
myinfo->basilisk_busy = 0;
}
void basilisk_p2p(void *_myinfo,void *_addr,char *senderip,uint8_t *data,int32_t datalen,char *type,int32_t encrypted)
int32_t basilisk_p2pQ_process(struct supernet_info *myinfo,int32_t maxiters)
{
uint32_t ipbits,basilisktag; int32_t msglen,len=0; void *ptr = 0; uint8_t space[4096]; bits256 senderpub; struct supernet_info *myinfo = _myinfo;
struct basilisk_p2pitem *ptr; char senderip[64]; uint32_t n=0,basilisktag,len = 0;
while ( n < maxiters && (ptr= queue_dequeue(&myinfo->p2pQ,0)) != 0 )
{
expand_ipbits(senderip,ptr->ipbits);
if ( ptr->type[0] == 'P' && ptr->type[1] == 'I' && ptr->type[2] == 'N' )
{
if ( strcmp(ptr->type,"PIN") == 0 && myinfo->NOTARY.RELAYID >= 0 )
basilisk_ping_process(myinfo,ptr->addr,ptr->ipbits,ptr->data,ptr->datalen);
}
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!=0?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!=0?senderip:"?");
}
free(ptr);
n++;
}
return(n);
}
struct basilisk_p2pitem *basilisk_p2pitem_create(void *_coin,void *_addr,char *type,uint32_t ipbits,uint8_t *data,int32_t datalen)
{
struct basilisk_p2pitem *ptr;
ptr = calloc(1,sizeof(*ptr) + datalen);
ptr->coin = _coin;
ptr->addr = _addr;
ptr->ipbits = ipbits;
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");
@ -781,37 +820,14 @@ void basilisk_p2p(void *_myinfo,void *_addr,char *senderip,uint8_t *data,int32_t
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;
if ( type[0] == 'P' && type[1] == 'I' && type[2] == 'N' )
{
if ( strcmp(type,"PIN") == 0 && myinfo->NOTARY.RELAYID >= 0 )
{
portable_mutex_lock(&myinfo->messagemutex);
basilisk_ping_process(myinfo,_addr,ipbits,data,datalen);
portable_mutex_unlock(&myinfo->messagemutex);
}
}
else
{
len += iguana_rwnum(0,data,sizeof(basilisktag),&basilisktag);
//int32_t i; for (i=0; i<datalen-len; i++)
// printf("%02x",data[len+i]);
if ( 0 && myinfo->IAMLP == 0 )
printf("RELAYID.%d ->received.%d basilisk_p2p.(%s) from %s tag.%u\n",myinfo->NOTARY.RELAYID,datalen,type,senderip!=0?senderip:"?",basilisktag);
if ( strcmp(type,"MSG") != 0 )//&& strcmp(type,"OUT") != 0 )
{
portable_mutex_lock(&myinfo->messagemutex);
basilisk_msgprocess(myinfo,_addr,ipbits,type,basilisktag,&data[len],datalen - len);
portable_mutex_unlock(&myinfo->messagemutex);
}
if ( 0 && myinfo->IAMLP == 0 )
printf("processed.%s from %s\n",type,senderip!=0?senderip:"?");
}
if ( ptr != 0 )
free(ptr);
ptr = basilisk_p2pitem_create(coin,addr,type,ipbits,data,datalen);
queue_enqueue("p2pQ",&myinfo->p2pQ,ptr,0);
}
void basilisk_requests_poll(struct supernet_info *myinfo)
@ -856,75 +872,78 @@ void basilisk_requests_poll(struct supernet_info *myinfo)
}
}
void basilisks_loop(void *arg)
{
struct iguana_info *virt,*tmpcoin,*notary; struct basilisk_message *msg,*tmpmsg; struct basilisk_item *tmp,*pending; uint32_t now; int32_t iter,maxmillis,flag=0; struct supernet_info *myinfo = arg;
iter = 0;
while ( 1 )
int32_t basilisk_issued_purge(struct supernet_info *myinfo,int32_t timepad)
{
struct basilisk_item *tmp,*pending; int32_t 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 || OS_milliseconds() > pending->expiration+600000) )
if ( pending != 0 && (pending->finished != 0 || startmilli > pending->expiration+timepad) )
{
//printf("enable free for HASH_DELETE.(%p)\n",pending);
HASH_DELETE(hh,myinfo->basilisks.issued,pending);
memset(pending,0,sizeof(*pending));
free(pending);
n++;
}
}
notary = iguana_coinfind("NOTARY");
now = (uint32_t)time(NULL);
portable_mutex_unlock(&myinfo->basilisk_mutex);
return(n);
}
void basilisk_iteration(struct supernet_info *myinfo)
{
struct iguana_info *virt,*tmpcoin,*notary; struct basilisk_message *msg,*tmpmsg; uint32_t now; int32_t maxmillis,flag=0;
now = (uint32_t)time(NULL);
notary = iguana_coinfind("NOTARY");
portable_mutex_lock(&myinfo->messagemutex);
HASH_ITER(hh,myinfo->messagetable,msg,tmpmsg)
{
if ( now > msg->expiration )
{
printf("delete expired message.%p QUEUEITEMS.%d\n",msg,QUEUEITEMS);
HASH_DELETE(hh,myinfo->messagetable,msg);
QUEUEITEMS--;
free(msg);
}
if ( myinfo->NOTARY.RELAYID >= 0 )
basilisk_ping_send(myinfo,notary);
}
portable_mutex_unlock(&myinfo->messagemutex);
if ( myinfo->NOTARY.RELAYID >= 0 )
{
if ( notary != 0 )
{
maxmillis = (1000 / (myinfo->allcoins_numvirts + 1)) + 1;
//portable_mutex_lock(&myinfo->allcoins_mutex);
HASH_ITER(hh,myinfo->allcoins,virt,tmpcoin)
{
if ( virt->started != 0 && virt->active != 0 && virt->virtualchain != 0 )
{
gecko_iteration(myinfo,notary,virt,maxmillis), flag++;
}
}
//portable_mutex_unlock(&myinfo->allcoins_mutex);
portable_mutex_lock(&myinfo->messagemutex);
basilisk_ping_send(myinfo,notary);
portable_mutex_unlock(&myinfo->messagemutex);
}
} // else printf("not notary %p %d\n",notary,myinfo->NOTARY.RELAYID);
else if ( myinfo->expiration != 0 )
{
/*HASH_ITER(hh,myinfo->allcoins,coin,tmpcoin)
{
if ( strcmp(coin->symbol,"NOTARY") != 0 && (myinfo->Cunspents == 0 || time(NULL) > coin->lastunspentsupdate+60) )
{
//printf(">>>>>>>>>>>>> update %s\n",coin->symbol);
basilisk_unspents_update(myinfo,coin);
coin->lastunspentsupdate = now;
//printf(">>>>>>>>>>>>> update %s finished\n",coin->symbol);
}
}*/
if ( myinfo->IAMLP != 0 || myinfo->DEXactive > now )
basilisk_requests_poll(myinfo);
}
portable_mutex_lock(&myinfo->messagemutex);
HASH_ITER(hh,myinfo->messagetable,msg,tmpmsg)
}
void basilisks_loop(void *arg)
{
if ( now > msg->expiration )
struct supernet_info *myinfo = arg; int32_t iter; double startmilli,endmilli;
iter = 0;
while ( 1 )
{
printf("delete expired message.%p QUEUEITEMS.%d\n",msg,QUEUEITEMS);
HASH_DELETE(hh,myinfo->messagetable,msg);
QUEUEITEMS--;
free(msg);
} //else printf("remains.%d\n",msg->expiration - now);
}
portable_mutex_unlock(&myinfo->messagemutex);
startmilli = OS_milliseconds();
basilisk_issued_purge(myinfo,600000);
basilisk_iteration(myinfo);
basilisk_p2pQ_process(myinfo,777);
if ( myinfo->NOTARY.RELAYID >= 0 )
usleep(500000);
else usleep(3000000);
endmilli = startmilli + 500;
else endmilli = startmilli + 2500;
while ( OS_milliseconds() < endmilli )
usleep(10000);
iter++;
}
}

2
basilisk/basilisk.h

@ -102,7 +102,7 @@ void basilisk_msgprocess(struct supernet_info *myinfo,void *addr,uint32_t sender
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)
void basilisks_init(struct supernet_info *myinfo);
void basilisk_p2p(void *myinfo,void *_addr,char *ipaddr,uint8_t *data,int32_t datalen,char *type,int32_t encrypted);
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);
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);
uint8_t *SuperNET_ciphercalc(void **ptrp,int32_t *cipherlenp,bits256 *privkeyp,bits256 *destpubkeyp,uint8_t *data,int32_t datalen,uint8_t *space2,int32_t space2size);

43
basilisk/basilisk_MSG.c

@ -15,7 +15,7 @@
// included from basilisk.c
char *basilisk_respond_addmessage(struct supernet_info *myinfo,uint8_t *key,int32_t keylen,uint8_t *data,int32_t datalen,int32_t sendping,uint32_t duration)
char *_basilisk_respond_addmessage(struct supernet_info *myinfo,uint8_t *key,int32_t keylen,uint8_t *data,int32_t datalen,int32_t sendping,uint32_t duration)
{
struct basilisk_message *msg; int32_t i; bits256 desthash;
if ( keylen != BASILISK_KEYSIZE )
@ -77,7 +77,7 @@ cJSON *basilisk_msgjson(struct basilisk_message *msg,uint8_t *key,int32_t keylen
return(msgjson);
}
cJSON *basilisk_respond_getmessage(struct supernet_info *myinfo,uint8_t *key,int32_t keylen)
cJSON *_basilisk_respond_getmessage(struct supernet_info *myinfo,uint8_t *key,int32_t keylen)
{
cJSON *msgjson = 0; struct basilisk_message *msg;
// portable_mutex_lock(&myinfo->messagemutex);
@ -122,7 +122,9 @@ char *basilisk_respond_OUT(struct supernet_info *myinfo,char *CMD,void *addr,cha
if ( duration > BASILISK_MSGDURATION )
duration = BASILISK_MSGDURATION;
}
retstr = basilisk_respond_addmessage(myinfo,key,keylen,data,datalen,1,duration);
portable_mutex_lock(&myinfo->messagemutex);
retstr = _basilisk_respond_addmessage(myinfo,key,keylen,data,datalen,1,duration);
portable_mutex_unlock(&myinfo->messagemutex);
// printf("OUT keylen.%d datalen.%d\n",keylen,datalen);
char str[65]; printf("add message.[%d] channel.%u msgid.%x %s\n",datalen,juint(valsobj,"channel"),juint(valsobj,"msgid"),bits256_str(str,hash));
return(retstr);
@ -147,7 +149,7 @@ int32_t basilisk_msgcmp(struct basilisk_message *msg,int32_t width,uint32_t chan
} else return(-3);
}
char *basilisk_iterate_MSG(struct supernet_info *myinfo,uint32_t channel,uint32_t msgid,bits256 srchash,bits256 desthash,int32_t origwidth)
char *_basilisk_iterate_MSG(struct supernet_info *myinfo,uint32_t channel,uint32_t msgid,bits256 srchash,bits256 desthash,int32_t origwidth)
{
uint8_t key[BASILISK_KEYSIZE]; int32_t allflag,i,keylen,width; cJSON *item,*retjson,*array; bits256 zero; struct basilisk_message *msg,*tmpmsg;
memset(zero.bytes,0,sizeof(zero));
@ -170,35 +172,35 @@ char *basilisk_iterate_MSG(struct supernet_info *myinfo,uint32_t channel,uint32_
if ( allflag != 0 )
break;
keylen = basilisk_messagekey(key,channel,msgid,srchash,desthash);
if ( (item= basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
if ( (item= _basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
jaddi(array,item);//, printf("gotmsg0.(%s)\n",jprint(item,0));
keylen = basilisk_messagekey(key,channel,msgid,desthash,srchash);
if ( (item= basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
if ( (item= _basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
jaddi(array,item);//, printf("gotmsg0.(%s)\n",jprint(item,0));
if ( origwidth > 0 )
{
if ( bits256_nonz(srchash) != 0 )
{
keylen = basilisk_messagekey(key,channel,msgid,zero,desthash);
if ( (item= basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
if ( (item= _basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
jaddi(array,item);//, printf("gotmsg1.(%s)\n",jprint(item,0));
keylen = basilisk_messagekey(key,channel,msgid,desthash,zero);
if ( (item= basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
if ( (item= _basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
jaddi(array,item);//, printf("gotmsg1.(%s)\n",jprint(item,0));
}
if ( bits256_nonz(desthash) != 0 )
{
keylen = basilisk_messagekey(key,channel,msgid,srchash,zero);
if ( (item= basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
if ( (item= _basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
jaddi(array,item);//, printf("gotmsg2.(%s)\n",jprint(item,0));
keylen = basilisk_messagekey(key,channel,msgid,zero,srchash);
if ( (item= basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
if ( (item= _basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
jaddi(array,item);//, printf("gotmsg2.(%s)\n",jprint(item,0));
}
if ( bits256_nonz(srchash) != 0 && bits256_nonz(desthash) != 0 )
{
keylen = basilisk_messagekey(key,channel,msgid,zero,zero);
if ( (item= basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
if ( (item= _basilisk_respond_getmessage(myinfo,key,keylen)) != 0 )
jaddi(array,item);//, printf("gotmsg3.(%s)\n",jprint(item,0));
}
}
@ -221,7 +223,9 @@ char *basilisk_respond_MSG(struct supernet_info *myinfo,char *CMD,void *addr,cha
msgid = juint(valsobj,"msgid");
channel = juint(valsobj,"channel");
//char str[65],str2[65]; printf("%s -> %s channel.%u msgid.%x width.%d\n",bits256_str(str,jbits256(valsobj,"sender")),bits256_str(str2,jbits256(valsobj,"desthash")),juint(valsobj,"channel"),msgid,width);
retstr = basilisk_iterate_MSG(myinfo,channel,msgid,jbits256(valsobj,"srchash"),jbits256(valsobj,"desthash"),width);
portable_mutex_lock(&myinfo->messagemutex);
retstr = _basilisk_iterate_MSG(myinfo,channel,msgid,jbits256(valsobj,"srchash"),jbits256(valsobj,"desthash"),width);
portable_mutex_unlock(&myinfo->messagemutex);
//printf("iterate_MSG.(%s)\n",retstr);
return(retstr);
}
@ -231,7 +235,7 @@ char *basilisk_respond_MSG(struct supernet_info *myinfo,char *CMD,void *addr,cha
HASH_ARRAY_STRING(basilisk,getmessage,hash,vals,hexstr)
{
uint32_t msgid,width,channel;
uint32_t msgid,width,channel; char *retstr;
if ( bits256_cmp(GENESIS_PUBKEY,jbits256(vals,"srchash")) == 0 )
jaddbits256(vals,"srchash",hash);
if ( bits256_cmp(GENESIS_PUBKEY,jbits256(vals,"desthash")) == 0 )
@ -246,7 +250,10 @@ HASH_ARRAY_STRING(basilisk,getmessage,hash,vals,hexstr)
{
channel = juint(vals,"channel");
width = juint(vals,"width");
return(basilisk_iterate_MSG(myinfo,channel,msgid,jbits256(vals,"srchash"),jbits256(vals,"desthash"),width));
portable_mutex_lock(&myinfo->messagemutex);
retstr = _basilisk_iterate_MSG(myinfo,channel,msgid,jbits256(vals,"srchash"),jbits256(vals,"desthash"),width);
portable_mutex_unlock(&myinfo->messagemutex);
return(retstr);
} else return(basilisk_standardservice("MSG",myinfo,0,jbits256(vals,"desthash"),vals,hexstr,1));
}
@ -258,7 +265,9 @@ HASH_ARRAY_STRING(basilisk,sendmessage,hash,vals,hexstr)
keylen = basilisk_messagekey(key,juint(vals,"channel"),juint(vals,"msgid"),jbits256(vals,"srchash"),jbits256(vals,"desthash"));
if ( (data= get_dataptr(BASILISK_HDROFFSET,&ptr,&datalen,space,sizeof(space),hexstr)) != 0 )
{
retstr = basilisk_respond_addmessage(myinfo,key,keylen,data,datalen,0,juint(vals,"duration"));
portable_mutex_lock(&myinfo->messagemutex);
retstr = _basilisk_respond_addmessage(myinfo,key,keylen,data,datalen,0,juint(vals,"duration"));
portable_mutex_unlock(&myinfo->messagemutex);
}
if ( ptr != 0 )
free(ptr);
@ -365,12 +374,14 @@ int32_t basilisk_process_retarray(struct supernet_info *myinfo,void *ptr,int32_t
{
duration = juint(item,"duration");
expiration = juint(item,"expiration");
if ( (retstr= basilisk_respond_addmessage(myinfo,key,BASILISK_KEYSIZE,data,datalen,0,duration)) != 0 )
portable_mutex_lock(&myinfo->messagemutex);
if ( (retstr= _basilisk_respond_addmessage(myinfo,key,BASILISK_KEYSIZE,data,datalen,0,duration)) != 0 )
{
if ( (*process_func)(myinfo,ptr,internal_func,channel,msgid,data,datalen,expiration,duration) < 0 )
errs++;
free(retstr);
} // else printf("duplicate.%d skipped\n",datalen);
portable_mutex_unlock(&myinfo->messagemutex);
}
}
//printf("n.%d maxlen.%d\n",n,maxlen);

8
basilisk/basilisk_ping.c

@ -105,7 +105,7 @@ int32_t basilisk_ping_genvirts(struct supernet_info *myinfo,uint8_t *data,int32_
}
#endif
int32_t basilisk_ping_processMSG(struct supernet_info *myinfo,uint32_t senderipbits,uint8_t *data,int32_t datalen)
int32_t _basilisk_ping_processMSG(struct supernet_info *myinfo,uint32_t senderipbits,uint8_t *data,int32_t datalen)
{
int32_t i,msglen,len=0; uint8_t num,keylen,*message,*key; uint32_t duration;
if ( (num= data[len++]) > 0 )
@ -134,7 +134,7 @@ int32_t basilisk_ping_processMSG(struct supernet_info *myinfo,uint32_t senderipb
return(0);
}
//printf("i.%d: keylen.%d msglen.%d\n",i,keylen,msglen);
basilisk_respond_addmessage(myinfo,key,keylen,message,msglen,0,duration);
_basilisk_respond_addmessage(myinfo,key,keylen,message,msglen,0,duration);
}
}
return(len);
@ -243,7 +243,9 @@ void basilisk_ping_process(struct supernet_info *myinfo,struct iguana_peer *addr
if ( len <= datalen-sizeof(sn) )
{
//len += basilisk_ping_processDEX(myinfo,senderipbits,&data[len],datalen-len);
len += basilisk_ping_processMSG(myinfo,senderipbits,&data[len],datalen-len);
portable_mutex_lock(&myinfo->messagemutex);
len += _basilisk_ping_processMSG(myinfo,senderipbits,&data[len],datalen-len);
portable_mutex_unlock(&myinfo->messagemutex);
}
//printf("PING got %d, processed.%d from (%s)\n",datalen,len,ipbuf);
//else printf("\n");

2
iguana/iguana777.h

@ -86,7 +86,7 @@ struct supernet_info
portable_mutex_t bu_mutex,allcoins_mutex,gecko_mutex,basilisk_mutex,DEX_mutex,DEX_reqmutex,DEX_swapmutex;
struct queueitem *DEX_quotes; cJSON *Cunspents,*Cspends;
struct basilisk_swap *swaps[256]; int32_t numswaps;
struct basilisk_message *messagetable; portable_mutex_t messagemutex; queue_t msgQ;
struct basilisk_message *messagetable; portable_mutex_t messagemutex; queue_t msgQ,p2pQ;
void *ctx;
uint8_t *pingbuf;
struct delayedPoW_info dPoW;

2
iguana/iguana_msg.c

@ -940,7 +940,7 @@ int32_t iguana_msgparser(struct supernet_info *myinfo,struct iguana_info *coin,s
} else ipaddr = 0;
len = recvlen;
//printf("GOT.(%s) len.%d from %s\n",H->command,recvlen,addr->ipaddr);
basilisk_p2p(myinfo,addr,ipaddr,data,recvlen,&H->command[strlen("SuperNET")],H->command[6] == 'e' && H->command[7] == 't');
basilisk_p2p(myinfo,coin,addr,ipaddr,data,recvlen,&H->command[strlen("SuperNET")],H->command[6] == 'e' && H->command[7] == 't');
return(0);
}
if ( addr != 0 )

8
includes/iguana_structs.h

@ -545,6 +545,14 @@ struct _gfshare_ctx
uint8_t sharenrs[255],buffer[];
};
struct basilisk_p2pitem
{
struct queueitem DL;
struct iguana_info *coin; struct iguana_peer *addr;
uint32_t ipbits,datalen; char type[4];
uint8_t data[];
};
struct basilisk_request
{
uint32_t requestid,timestamp,quoteid,quotetime; // 0 to 15

Loading…
Cancel
Save