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.

1257 lines
60 KiB

9 years ago
/******************************************************************************
9 years ago
* Copyright © 2014-2016 The SuperNET Developers. *
9 years ago
* *
* 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 "iguana777.h"
int32_t iguana_rwaddr(int32_t rwflag,uint8_t *serialized,struct iguana_msgaddress *addr,int32_t protover)
{
int32_t len = 0;
if ( protover >= CADDR_TIME_VERSION )
len += iguana_rwnum(rwflag,&serialized[len],sizeof(addr->nTime),&addr->nTime);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(addr->nServices),&addr->nServices);
len += iguana_rwmem(rwflag,&serialized[len],sizeof(addr->ip),&addr->ip);
if ( rwflag != 0 )
len += iguana_rwnum(rwflag,&serialized[len],sizeof(addr->port),&addr->port);
else
{
addr->port = (uint16_t)serialized[len++] << 8;
addr->port += (uint16_t)serialized[len++];
}
return(len);
}
int32_t iguana_rwversion(int32_t rwflag,uint8_t *serialized,struct iguana_msgversion *msg,char *ipaddr,int32_t readsize)
9 years ago
{
int32_t len = 0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->nVersion),&msg->nVersion);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->nServices),&msg->nServices);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->nTime),&msg->nTime);
len += iguana_rwaddr(rwflag,&serialized[len],&msg->addrTo,MIN_PROTO_VERSION);
len += iguana_rwaddr(rwflag,&serialized[len],&msg->addrFrom,MIN_PROTO_VERSION);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->nonce),&msg->nonce);
9 years ago
len += iguana_rwvarstr(rwflag,&serialized[len],sizeof(msg->strSubVer),msg->strSubVer);
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->nStartingHeight),&msg->nStartingHeight);
if ( readsize == 117 )
{
9 years ago
uint32_t iVer = 1132,v_Network_id=1; uint16_t wPort=1920,wCtPort=0,wPrPort=0; uint8_t bIsGui=0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(iVer),&iVer);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(v_Network_id),&v_Network_id);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(wPort),&wPort);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(bIsGui),&bIsGui);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(wCtPort),&wCtPort);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(wPrPort),&wPrPort);
/*int iVer = BitNet_Version;
9 years ago
unsigned short wPort = GetListenPort();
unsigned char bIsGui = 0; // 2014.12.18 add
unsigned short wCtPort = 0;
unsigned short wPrPort = 0;
vRecv >> iVer;
pfrom->vBitNet.v_iVersion = iVer;
vRecv >> pfrom->vBitNet.;
if (!vRecv.empty()){ vRecv >> pfrom->vBitNet.v_ListenPort; }
if (!vRecv.empty()){ vRecv >> pfrom->vBitNet.v_IsGuiNode; } //-- 2014.12.18 add
if (!vRecv.empty()){ vRecv >> pfrom->vBitNet.v_iVpnServiceCtrlPort; } //-- 2014.12.28 add
if (!vRecv.empty()){ vRecv >> pfrom->vBitNet.v_P2P_proxy_port; } //-- 2014.12.28 add
*/
printf("iVer.%d v_Network_id.%d wPort.%u bIsGui.%d wCtPort.%u wPrPort.%u\n",iVer,v_Network_id,wPort,bIsGui,wCtPort,wPrPort);
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->relayflag),&msg->relayflag);
}
8 years ago
else if ( msg->nVersion > 70002 )
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->relayflag),&msg->relayflag);
9 years ago
//if ( rwflag == 0 )
9 years ago
//printf("readsize.%d %-15s v.%llu srv.%llx %u ht.%llu [%s].R%d nonce.%llx\n",readsize,ipaddr,(long long)msg->nVersion,(long long)msg->nServices,(uint32_t)msg->nTime,(long long)msg->nStartingHeight,msg->strSubVer,msg->relayflag,(long long)msg->nonce);
9 years ago
return(len);
}
9 years ago
int32_t iguana_rwmerklebranch(int32_t rwflag,uint8_t *serialized,struct iguana_msgmerkle *msg)
9 years ago
{
9 years ago
int32_t i,len = 0;
len += iguana_rwvarint32(rwflag,&serialized[len],&msg->branch_length);
if ( msg->branch_length < sizeof(msg->branch_hash)/sizeof(*msg->branch_hash) )
{
for (i=0; i<msg->branch_length; i++)
{
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->branch_hash[i]),msg->branch_hash[i].bytes);
}
} else return(1000000);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->branch_side_mask),&msg->branch_side_mask);
//printf("branch_length.%d side_mask.%x\n",msg->branch_length,msg->branch_side_mask);
return(len);
}
int32_t iguana_rwzsolution(int32_t rwflag,uint8_t *serialized,uint8_t *solution,int32_t n)
9 years ago
{
int32_t i,len = 0;
for (i=0; i<n; i++)
len += iguana_rwnum(rwflag,&serialized[len],sizeof(solution[i]),&solution[i]);
return(len);
}
int32_t iguana_rwblockhdr(int32_t rwflag,uint8_t zcash,uint8_t *serialized,struct iguana_msgzblock *zmsg)
{
uint32_t tmp; struct iguana_msgblock *msg = (void *)zmsg; int32_t len = 0;
if ( zcash == 0 )
8 years ago
{
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->H.version),&msg->H.version);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->H.prev_block),msg->H.prev_block.bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->H.merkle_root),msg->H.merkle_root.bytes);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->H.timestamp),&msg->H.timestamp);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->H.bits),&msg->H.bits);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->H.nonce),&msg->H.nonce);
8 years ago
}
else
{
8 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(zmsg->zH.version),&zmsg->zH.version);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(zmsg->zH.prev_block),zmsg->zH.prev_block.bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(zmsg->zH.merkle_root),zmsg->zH.merkle_root.bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(zmsg->zH.reserved),zmsg->zH.reserved.bytes);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(zmsg->zH.timestamp),&zmsg->zH.timestamp);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(zmsg->zH.bits),&zmsg->zH.bits);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(zmsg->zH.bignonce),zmsg->zH.bignonce.bytes);
//char str[65]; printf("prev.(%s) len.%d [%d %d %d]\n",bits256_str(str,msg->H.prev_block),len,serialized[len],serialized[len+1],serialized[len+2]);
if ( rwflag != 0 )
8 years ago
memcpy(&serialized[len],zmsg->zH.var_numelements,sizeof(zmsg->zH.var_numelements));
else memcpy(zmsg->zH.var_numelements,&serialized[len],sizeof(zmsg->zH.var_numelements));
//printf("numelements: (%02x %02x %02x)\n",serialized[len],serialized[len+1],serialized[len+2]);
8 years ago
len += sizeof(zmsg->zH.var_numelements);
if ( iguana_rwvarint32(0,zmsg->zH.var_numelements,(uint32_t *)&tmp) != sizeof(zmsg->zH.var_numelements) )
printf("rw.%d unexpected varint size for zmsg.zH.numelements <- %d %d %d\n",rwflag,zmsg->zH.var_numelements[0],zmsg->zH.var_numelements[1],zmsg->zH.var_numelements[2]);
8 years ago
if ( tmp != ZCASH_SOLUTION_ELEMENTS )
{
int32_t i; for (i=0; i<157; i++)
printf("%02x",serialized[i]);
printf(" rw.%d unexpected ZCASH_SOLUTION_ELEMENTS, (%02x %02x %02x) expected %d tmp.%d len.%d\n",rwflag,zmsg->zH.var_numelements[0],zmsg->zH.var_numelements[1],zmsg->zH.var_numelements[2],ZCASH_SOLUTION_ELEMENTS,tmp,len);
return(-1);
}
8 years ago
len += iguana_rwzsolution(rwflag,&serialized[len],zmsg->zH.solution,tmp);
}
9 years ago
return(len);
}
8 years ago
int32_t iguana_eatauxpow(struct supernet_info *myinfo,int32_t rwflag,char *symbol,uint8_t zcash,uint8_t *serialized,int32_t maxlen)
9 years ago
{
int32_t len = 0; void *ptr; struct iguana_msgtx msg; struct OS_memspace MEM; bits256 auxhash2,coinbasetxid; struct iguana_msgmerkle *coinbase_branch,*blockchain_branch; struct iguana_msgblock parentblock; struct iguana_info *coin;
9 years ago
if ( rwflag == 0 && (coin= iguana_coinfind(symbol)) != 0 && coin->chain->auxpow != 0 )
{
memset(&msg,0,sizeof(msg));
coinbase_branch = calloc(1,sizeof(*coinbase_branch));
blockchain_branch = calloc(1,sizeof(*blockchain_branch));
9 years ago
memset(&parentblock,0,sizeof(parentblock));
memset(&MEM,0,sizeof(MEM));
ptr = calloc(1,1000000);
iguana_meminit(&MEM,"auxpow",ptr,1000000,0);
8 years ago
len += iguana_rwtx(myinfo,coin->chain->zcash,rwflag,coin,&MEM,&serialized[len],&msg,(int32_t)MEM.totalsize,&coinbasetxid,coin->chain->isPoS,0);
if ( len > maxlen )
return(-1);
9 years ago
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(auxhash2),auxhash2.bytes);
if ( len > maxlen )
return(-1);
len += iguana_rwmerklebranch(rwflag,&serialized[len],coinbase_branch);
if ( len > maxlen )
return(-1);
len += iguana_rwmerklebranch(rwflag,&serialized[len],blockchain_branch);
if ( len > maxlen )
return(-1);
len += iguana_rwblockhdr(rwflag,zcash,&serialized[len],(void *)&parentblock);
if ( len > maxlen )
return(-1);
9 years ago
free(ptr);
free(coinbase_branch);
free(blockchain_branch);
9 years ago
}
return(len);
}
8 years ago
int32_t iguana_blockhdrsize(char *symbol,uint8_t zcash,uint8_t auxpow)
{
int32_t len = 0;
if ( zcash == 0 )
{
if ( auxpow == 0 )
return(sizeof(struct iguana_msgblockhdr));
//if ( (len= iguana_eatauxpow(0,symbol,&serialized[sizeof(struct iguana_msgblockhdr)],(int32_t)(maxlen-sizeof(struct iguana_msgblockhdr)))) > 0 )
return(sizeof(struct iguana_msgblockhdr) + len);
//else
return(-1);
8 years ago
} else return((int32_t)(sizeof(struct iguana_msgzblockhdr) + auxpow*sizeof(bits256)));
}
int32_t iguana_rwblock(struct supernet_info *myinfo,char *symbol,uint8_t zcash,uint8_t auxpow,int32_t (*hashalgo)(uint8_t *blockhashp,uint8_t *serialized,int32_t len),int32_t rwflag,bits256 *hash2p,uint8_t *serialized,struct iguana_msgzblock *zmsg,int32_t maxlen)
9 years ago
{
int32_t len = 0; uint64_t x; struct iguana_msgblock *msg = (void *)zmsg;
if ( (len= iguana_rwblockhdr(rwflag,zcash,serialized,zmsg)) < 0 )
{
8 years ago
int32_t i;
for (i=0; i<maxlen&&i<sizeof(struct iguana_zblock); i++)
8 years ago
printf("%02x",serialized[i]);
printf(" error rw.%d blockhdr zcash.%d\n",rwflag,zcash);
return(-1);
}
9 years ago
*hash2p = iguana_calcblockhash(symbol,hashalgo,serialized,len);
8 years ago
if ( auxpow != 0 && (msg->H.version & 0x100) != 0 )
8 years ago
len += iguana_eatauxpow(myinfo,rwflag,symbol,zcash,&serialized[len],maxlen-len);
if ( rwflag == 1 )
{
if ( zcash == 0 )
8 years ago
x = zmsg->txn_count;
else x = msg->txn_count;
}
//char str[65],str2[65]; printf("zcash.%d len.%d: block version.%d timestamp.%u bits.%x nonce.%u prev.(%s) %llx hash2.%s zlen.%d\n",zcash,len,msg->H.version,msg->H.timestamp,msg->H.bits,msg->H.nonce,bits256_str(str,msg->H.prev_block),(long long)msg->H.merkle_root.txid,bits256_str(str2,*hash2p),(int32_t)sizeof(struct iguana_msgzblockhdr));
9 years ago
len += iguana_rwvarint(rwflag,&serialized[len],&x);
if ( rwflag == 0 )
{
char str[65];
bits256_str(str,*hash2p);
if ( x < 65536 )
{
if ( zcash != 0 )
8 years ago
zmsg->txn_count = (uint16_t)x;
else msg->txn_count = (uint16_t)x;
} else printf("txn_count overflow.%lld for %s\n",(long long)x,str);
9 years ago
}
// ? txns tx[] Block transactions, in format of "tx" command
return(len);
}
8 years ago
int32_t iguana_serialize_block(struct supernet_info *myinfo,struct iguana_chain *chain,bits256 *hash2p,uint8_t serialized[sizeof(struct iguana_msgzblock)],struct iguana_block *block)
9 years ago
{
struct iguana_msgzblock zmsg; struct iguana_msgblock *msg = (void *)&zmsg; struct iguana_zblock *zblock; int32_t i,len;
if ( chain->zcash == 0 )
8 years ago
{
memset(msg,0,sizeof(*msg));
msg->H.version = block->RO.version;
msg->H.prev_block = block->RO.prev_block;
msg->H.merkle_root = block->RO.merkle_root;
msg->H.timestamp = block->RO.timestamp;
msg->H.bits = block->RO.bits;
msg->H.nonce = block->RO.nonce;
msg->txn_count = block->RO.txn_count;
len = iguana_rwblock(myinfo,chain->symbol,chain->zcash,chain->auxpow,chain->hashalgo,1,hash2p,serialized,&zmsg,IGUANA_MAXPACKETSIZE);
8 years ago
}
else
{
8 years ago
memset(&zmsg,0,sizeof(zmsg));
zblock = (void *)block;
zmsg.zH.version = zblock->RO.version;
zmsg.zH.prev_block = zblock->RO.prev_block;
zmsg.zH.merkle_root = zblock->RO.merkle_root;
zmsg.zH.timestamp = zblock->RO.timestamp;
zmsg.zH.bits = zblock->RO.bits;
zmsg.zH.bignonce = zblock->zRO.bignonce;
if ( iguana_rwvarint32(1,zmsg.zH.var_numelements,(uint32_t *)&zblock->zRO.numelements) != sizeof(zmsg.zH.var_numelements) )
{
// printf("unexpected varint size for zmsg.zH.numelements <- %d %d %d\n",zmsg.zH.var_numelements[0],zmsg.zH.var_numelements[1],zmsg.zH.var_numelements[2]);
}
if ( zblock->zRO.numelements == ZCASH_SOLUTION_ELEMENTS )
{
for (i=0; i<ZCASH_SOLUTION_ELEMENTS; i++)
zmsg.zH.solution[i] = zblock->zRO.solution[i];
zmsg.txn_count = block->RO.txn_count;
len = iguana_rwblock(myinfo,chain->symbol,chain->zcash,chain->auxpow,chain->hashalgo,1,hash2p,serialized,(void *)&zmsg,IGUANA_MAXPACKETSIZE);
} else return(-1);
8 years ago
}
9 years ago
return(len);
9 years ago
}
int32_t iguana_rwblockhash(int32_t rwflag,uint8_t *serialized,uint32_t *nVersionp,uint32_t *varintp,bits256 *hashes,bits256 *stophash)
{
int32_t i,len = 0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(*nVersionp),nVersionp);
len += iguana_rwvarint32(rwflag,&serialized[len],varintp);
if ( *varintp < IGUANA_MAXBUNDLESIZE+1 )
{
for (i=0; i<*varintp; i++)
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(hashes[i]),hashes[i].bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(*stophash),stophash->bytes);
//for (i=0; i<len; i++)
// printf("%02x ",serialized[i]);
//printf("rwblockhash len.%d\n",len);
} else printf("iguana_rwblockhash: illegal varint.%d\n",*varintp);
return(len);
}
9 years ago
int32_t iguana_rwmsgalert(struct iguana_info *coin,int32_t rwflag,uint8_t *serialized,struct iguana_msgalert *msg)
{
bits256 alerthash2; int32_t i,plen,isvalid,len = 0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->version),&msg->version);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->relayuntil),&msg->relayuntil);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->expiration),&msg->expiration);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->ID),&msg->ID);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->cancel),&msg->cancel);
len += iguana_rwvarint32(rwflag,&serialized[len],&msg->numcancellist);
if ( msg->numcancellist != 0 )
{
for (i=0; i<msg->numcancellist; i++)
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->version),&msg->list[i]);
}
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->minver),&msg->minver);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->maxver),&msg->maxver);
len += iguana_rwvarint32(rwflag,&serialized[len],&msg->setsubvervar);
len += iguana_rwvarstr(rwflag,&serialized[len],sizeof(msg->subver),msg->subver);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->priority),&msg->priority);
len += iguana_rwvarstr(rwflag,&serialized[len],sizeof(msg->comment),msg->comment);
len += iguana_rwvarstr(rwflag,&serialized[len],sizeof(msg->statusbar),msg->statusbar);
len += iguana_rwvarstr(rwflag,&serialized[len],sizeof(msg->reserved),msg->reserved);
alerthash2 = bits256_doublesha256(0,serialized,len);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->siglen),&msg->siglen);
if ( msg->siglen >= 70 && msg->siglen < 74 )
{
if ( rwflag == 0 )
memcpy(msg->sig,&serialized[len],msg->siglen);
else memcpy(&serialized[len],msg->sig,msg->siglen);
len += msg->siglen;
plen = bitcoin_pubkeylen(coin->chain->alertpubkey);
isvalid = (bitcoin_verify(coin->ctx,msg->sig,msg->siglen,alerthash2,coin->chain->alertpubkey,plen) == 0);
for (i=0; i<msg->siglen; i++)
printf("%02x",msg->sig[i]);
printf(" %s\n",isvalid != 0 ? "VALIDSIG" : "SIGERROR");
for (i=0; i<plen; i++)
printf("%02x",coin->chain->alertpubkey[i]);
char str[65]; printf(" alertpubkey.%d, alerthash2.%s\n",plen,bits256_str(str,alerthash2));
} else msg->siglen = 0;
9 years ago
printf(" ALERT v.%d relay.%lld expires.%lld ID.%d cancel.%d numlist.%d minver.%d maxver.%d subver.(%s) priority.%d comment.(%s) STATUS.(%s) reserved.(%s)\n",msg->version,(long long)msg->relayuntil,(long long)msg->expiration,msg->ID,msg->cancel,msg->numcancellist,msg->minver,msg->maxver,msg->subver,msg->priority,msg->comment,msg->statusbar,msg->reserved);
9 years ago
return(len);
}
9 years ago
/*int32_t iguana_request_data(struct iguana_info *coin,struct iguana_peer *addr,bits256 *hashes,int32_t n,uint32_t type,int32_t forceflag)
9 years ago
{
uint32_t len,i; uint8_t serialized[sizeof(struct iguana_msghdr) + (sizeof(uint32_t) + sizeof(bits256))*32 + sizeof(uint64_t)];
if ( addr == 0 )
return(-1);
len = iguana_rwvarint32(1,&serialized[sizeof(struct iguana_msghdr)],(uint32_t *)&n);
for (i=0; i<n; i++)
{
len += iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr) + len],sizeof(uint32_t),&type);
len += iguana_rwbignum(1,&serialized[sizeof(struct iguana_msghdr) + len],sizeof(bits256),hashes[i].bytes);
}
//printf("iguana_request_data.%d %s ht.%d\n",n,bits256_str(hashes[0]),iguana_height(coin,hashes[0]));
addr->getdatamillis = milliseconds();
9 years ago
len = iguana_queue_send(addr,0,serialized,"getdata",len,iguana_height(coin,hashes[n-1]),forceflag);
9 years ago
return(len);
}*/
9 years ago
9 years ago
void iguana_gotversion(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,struct iguana_msgversion *vers)
9 years ago
{
8 years ago
uint8_t serialized[sizeof(struct iguana_msghdr)];
8 years ago
//printf("gotversion from %s: starting height.%d services.%llx proto.%d (%s)\n",addr->ipaddr,vers->nStartingHeight,(long long)vers->nServices,vers->nVersion,vers->strSubVer);
8 years ago
if ( strncmp(vers->strSubVer,"/iguana",strlen("/iguana")) == 0 )
9 years ago
addr->supernet = 1, addr->basilisk = 0;
else if ( strncmp(vers->strSubVer,"/basilisk",strlen("/basilisk")) == 0 )
8 years ago
{
9 years ago
addr->basilisk = 1, addr->supernet = 0;
8 years ago
}
8 years ago
//if ( (vers->nServices & NODE_NETWORK) != 0 )
9 years ago
{
addr->protover = (vers->nVersion < PROTOCOL_VERSION) ? vers->nVersion : PROTOCOL_VERSION;
9 years ago
//printf("(%s) proto.%d -> %d\n",addr->ipaddr,vers->nVersion,addr->protover);
9 years ago
addr->relayflag = vers->relayflag;
addr->height = vers->nStartingHeight;
addr->relayflag = 1;
iguana_gotdata(coin,addr,addr->height);
9 years ago
}
8 years ago
iguana_queue_send(addr,0,serialized,"verack",0);
8 years ago
if ( addr->supernet != 0 || addr->basilisk != 0 )
printf("height.%d nServices.%lld nonce.%llu %srelay node.(%s) supernet.%d basilisk.%d longest.%u\n",vers->nStartingHeight,(long long)vers->nServices,(long long)vers->nonce,addr->relayflag==0?"non-":"",addr->ipaddr,addr->supernet,addr->basilisk,vers->nStartingHeight);
9 years ago
if ( (int32_t)vers->nStartingHeight > coin->longestchain )
9 years ago
{
9 years ago
if ( coin->badlongestchain != 0 && (int32_t)vers->nStartingHeight >= coin->badlongestchain )
9 years ago
{
printf("peer.(%s) gives badlongestchain.%d\n",addr->ipaddr,vers->nStartingHeight);
addr->dead = 1;
} //else coin->longestchain = vers->nStartingHeight;
9 years ago
}
8 years ago
if ( addr->msgcounts.verack == 0 && time(NULL) > addr->ready+600 )
8 years ago
iguana_send_version(coin,addr,coin->myservices);
9 years ago
iguana_queue_send(addr,0,serialized,"getaddr",0);
9 years ago
}
int32_t iguana_send_version(struct iguana_info *coin,struct iguana_peer *addr,uint64_t myservices)
{
int32_t len; struct iguana_msgversion msg; uint8_t serialized[sizeof(struct iguana_msghdr)+sizeof(msg)];
memset(&msg,0,sizeof(msg));
8 years ago
msg.nVersion = coin->chain->protover;//PROTOCOL_VERSION;
9 years ago
msg.nServices = (myservices & NODE_NETWORK);
9 years ago
msg.nTime = (int64_t)time(NULL);
msg.nonce = coin->instance_nonce;
8 years ago
if ( coin->FULLNODE != 0 || coin->VALIDATENODE != 0 )
9 years ago
sprintf(msg.strSubVer,"/iguana 0.00/");
else sprintf(msg.strSubVer,"/basilisk 0.00/");
8 years ago
//printf("SEND.(%s) -> (%s)\n",msg.strSubVer,addr->ipaddr);
9 years ago
//sprintf(msg.strSubVer,"/Satoshi:0.10.0/");
9 years ago
msg.nStartingHeight = coin->blocks.hwmchain.height;
iguana_gotdata(coin,addr,msg.nStartingHeight);
len = iguana_rwversion(1,&serialized[sizeof(struct iguana_msghdr)],&msg,addr->ipaddr,0);
9 years ago
return(iguana_queue_send(addr,0,serialized,"version",len));
9 years ago
}
9 years ago
int32_t iguana_send_VPNversion(struct iguana_info *coin,struct iguana_peer *addr,uint64_t myservices)
{
int32_t len; struct iguana_VPNversion msg; uint8_t serialized[sizeof(struct iguana_msghdr)+sizeof(msg)];
memset(&msg,0,sizeof(msg));
msg.nVersion = PROTOCOL_VERSION;
9 years ago
msg.nServices = (myservices & NODE_NETWORK);
9 years ago
msg.nTime = (int64_t)time(NULL);
9 years ago
msg.nonce = 0;//coin->instance_nonce;
8 years ago
if ( coin->FULLNODE != 0 || coin->VALIDATENODE != 0 )
9 years ago
sprintf(msg.strSubVer,"/iguana 0.00/");
else sprintf(msg.strSubVer,"/basilisk 0.00/");
9 years ago
msg.nStartingHeight = coin->blocks.hwmchain.height;
len = iguana_rwversion(1,&serialized[sizeof(struct iguana_msghdr)],(void *)&msg,addr->ipaddr,117);
9 years ago
return(iguana_queue_send(addr,0,serialized,"version",len));
9 years ago
}
9 years ago
void iguana_supernet_ping(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr)
9 years ago
{
if ( addr->supernet != 0 || addr->basilisk != 0 )
{
8 years ago
//if ( coin->FULLNODE != 0 )
9 years ago
// basilisk_relays_send(myinfo,addr);
9 years ago
//printf("send getpeers to %s\n",addr->ipaddr);
9 years ago
//printf("maybe send basilisk ping here?\n");
9 years ago
//iguana_send_supernet(addr,SUPERNET_GETPEERSTR,0);
}
}
9 years ago
void iguana_gotverack(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr)
9 years ago
{
9 years ago
uint8_t serialized[sizeof(struct iguana_msghdr)];
9 years ago
if ( addr != 0 )
{
8 years ago
if ( addr->supernet != 0 || addr->basilisk != 0 )
printf(">>>>>>>>>> supernet.%d basilisk.%d gotverack from %s\n",addr->supernet,addr->basilisk,addr->ipaddr);
9 years ago
addr->A.nTime = (uint32_t)time(NULL);
9 years ago
iguana_queue_send(addr,0,serialized,"getaddr",0);
9 years ago
iguana_supernet_ping(myinfo,coin,addr);
9 years ago
}
}
void iguana_gotaddr(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_msgaddress *A)
{
9 years ago
char ipaddr[64],ipport[64]; uint32_t ipbits; uint16_t port;
9 years ago
iguana_rwnum(0,&A->ip[12],sizeof(uint32_t),&ipbits);
9 years ago
iguana_rwnum(0,(void *)&A->port,sizeof(uint16_t),&port);
9 years ago
expand_ipbits(ipaddr,ipbits);
9 years ago
if ( port != 0 )
sprintf(ipport,"%s:%d",ipaddr,port);
9 years ago
if ( 0 )
{
int32_t i;
printf("{{");
for (i=0; i<16; i++)
printf("0x%02x%s",A->ip[i],i<15?",":"");
printf("}, 14631},\n");
}
8 years ago
if ( strcmp(coin->symbol,"BTC") != 0 || (rand() % 10) == 0 )
iguana_possible_peer(coin,ipport);
if ( 0 && strcmp("TAZ",coin->symbol) == 0 )
printf("iguana_gotaddr: %s from %s\n",ipaddr,addr->ipaddr);
9 years ago
}
9 years ago
void iguana_gotping(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,uint64_t nonce,uint8_t *data)
9 years ago
{
9 years ago
int32_t len; uint8_t serialized[sizeof(struct iguana_msghdr) + sizeof(nonce)];
9 years ago
len = iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr)],sizeof(uint64_t),&nonce);
if ( memcmp(data,&serialized[sizeof(struct iguana_msghdr)],sizeof(nonce)) != 0 )
printf("ping ser error %llx != %llx\n",(long long)nonce,*(long long *)data);
9 years ago
iguana_queue_send(addr,0,serialized,"pong",len);
9 years ago
iguana_supernet_ping(myinfo,coin,addr);
9 years ago
}
9 years ago
int32_t iguana_send_ping(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr)
9 years ago
{
int32_t len; uint64_t nonce; uint8_t serialized[sizeof(struct iguana_msghdr) + sizeof(nonce)];
8 years ago
if ( addr->msgcounts.verack == 0 )
{
8 years ago
if ( strcmp(addr->ipaddr,myinfo->ipaddr) != 0 )
{
printf("%s send version instead of ping to %s\n",coin->symbol,addr->ipaddr);
return(iguana_send_version(coin,addr,coin->myservices));
}
8 years ago
}
9 years ago
if ( (nonce= addr->pingnonce) == 0 )
{
OS_randombytes((uint8_t *)&nonce,sizeof(nonce));
9 years ago
addr->pingnonce = ((nonce & 0xffffffff) << 32) | ((uint32_t)addr->ipbits & 0xffffffff);
9 years ago
addr->pingtime = (uint32_t)time(NULL);
}
9 years ago
//printf("pingnonce.%llx from (%s)\n",(long long)nonce,addr->ipaddr);
9 years ago
iguana_queue_send(addr,0,serialized,"getaddr",0);
9 years ago
len = iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr)],sizeof(uint64_t),&nonce);
9 years ago
iguana_supernet_ping(myinfo,coin,addr);
9 years ago
//if ( myinfo->IAMRELAY != 0 )
// basilisk_relays_send(myinfo,addr);
9 years ago
return(iguana_queue_send(addr,0,serialized,"ping",len));
9 years ago
}
int32_t iguana_send_ConnectTo(struct iguana_info *coin,struct iguana_peer *addr)
{
int32_t len; uint32_t r; uint16_t port = 1920; uint8_t serialized[sizeof(struct iguana_msghdr) + 6];
r = rand();
len = iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr)],sizeof(uint32_t),&r);
len += iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr)+len],sizeof(port),&port);
9 years ago
return(iguana_queue_send(addr,0,serialized,"ConnectTo",len));
}
9 years ago
void iguana_gotpong(struct iguana_info *coin,struct iguana_peer *addr,uint64_t nonce)
{
if ( addr->sendmillis != 0 )
{
addr->pingtime = (OS_milliseconds() - addr->sendmillis) + 1;
addr->pingsum += addr->pingtime, addr->numpings++;
9 years ago
//printf("%s pingtime %.0f numpings.%d [%.3f] ",addr->ipaddr,addr->pingtime,addr->numpings,addr->pingsum/addr->numpings);
9 years ago
}
if ( nonce != addr->pingnonce )
{
9 years ago
// printf("pong received invalid pingnonce (%s) %llx vs %llx\n",addr->ipaddr,(long long)addr->pingnonce,(long long)nonce);
9 years ago
} else printf("(%s) pong verified with pingnonce.%llx\n",addr->ipaddr,(long long)addr->pingnonce);
addr->pingnonce = 0;
addr->sendmillis = 0;
}
int32_t iguana_gethdrs(struct iguana_info *coin,uint8_t *serialized,char *cmd,char *hashstr)
{
uint32_t len,n; bits256 hash2; bits256 zero;
decode_hex(hash2.bytes,sizeof(hash2),hashstr);
memset(zero.bytes,0,sizeof(zero));
n = 0;
len = iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr)],sizeof(uint32_t),&n);
n++;
len += iguana_rwvarint32(1,&serialized[sizeof(struct iguana_msghdr) + len],(uint32_t *)&n);
len += iguana_rwbignum(1,&serialized[sizeof(struct iguana_msghdr) + len],sizeof(bits256),hash2.bytes);
len += iguana_rwbignum(1,&serialized[sizeof(struct iguana_msghdr) + len],sizeof(bits256),(uint8_t *)zero.bytes);
return(iguana_sethdr((void *)serialized,coin->chain->netmagic,cmd,&serialized[sizeof(struct iguana_msghdr)],len));
}
9 years ago
int32_t iguana_getdata(struct iguana_info *coin,uint8_t *serialized,int32_t type,bits256 *hashes,int32_t n)
9 years ago
{
9 years ago
uint32_t len,i; //bits256 hash2;
9 years ago
len = iguana_rwvarint32(1,&serialized[sizeof(struct iguana_msghdr)],(uint32_t *)&n);
for (i=0; i<n; i++)
{
len += iguana_rwnum(1,&serialized[sizeof(struct iguana_msghdr) + len],sizeof(uint32_t),&type);
9 years ago
len += iguana_rwbignum(1,&serialized[sizeof(struct iguana_msghdr) + len],sizeof(bits256),hashes[i].bytes);
9 years ago
}
return(iguana_sethdr((void *)serialized,coin->chain->netmagic,"getdata",&serialized[sizeof(struct iguana_msghdr)],len));
}
8 years ago
int32_t debugtest;
8 years ago
int32_t iguana_rwvin(int32_t rwflag,struct iguana_info *coin,struct OS_memspace *mem,uint8_t *serialized,struct iguana_msgvin *msg,int32_t vini)
9 years ago
{
9 years ago
int32_t len = 0; uint32_t tmp;
9 years ago
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->prev_hash),msg->prev_hash.bytes);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->prev_vout),&msg->prev_vout);
9 years ago
if ( rwflag == 1 )
tmp = msg->scriptlen;
len += iguana_rwvarint32(rwflag,&serialized[len],&tmp);
9 years ago
if ( rwflag == 0 )
9 years ago
{
msg->scriptlen = tmp;
8 years ago
if ( msg->scriptlen < IGUANA_MAXSCRIPTSIZE )
msg->vinscript = iguana_memalloc(mem,msg->scriptlen,1);
else return(0);
9 years ago
}
len += iguana_rwmem(rwflag,&serialized[len],msg->scriptlen,msg->vinscript);
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->sequence),&msg->sequence);
8 years ago
if ( debugtest != 0 )
{
char str[65]; printf("MSGvin.(%s/v%d) script[%d]\n",bits256_str(str,msg->prev_hash),msg->prev_vout,msg->scriptlen);
int i; for (i=0; i<msg->scriptlen; i++)
printf("%02x ",msg->vinscript[i]);
printf(" vinscriptlen.%d, prevhash.%llx prev_vout.%d | ",msg->scriptlen,(long long)msg->prev_hash.txid,msg->prev_vout);
}
9 years ago
return(len);
}
int32_t iguana_rwvout(int32_t rwflag,struct OS_memspace *mem,uint8_t *serialized,struct iguana_msgvout *msg)
{
int32_t len = 0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->value),&msg->value);
len += iguana_rwvarint32(rwflag,&serialized[len],&msg->pk_scriptlen);
9 years ago
if ( msg->pk_scriptlen > IGUANA_MAXSCRIPTSIZE )
8 years ago
return(0);
9 years ago
if ( rwflag == 0 )
msg->pk_script = iguana_memalloc(mem,msg->pk_scriptlen,1);
len += iguana_rwmem(rwflag,&serialized[len],msg->pk_scriptlen,msg->pk_script);
9 years ago
if ( debugtest != 0 )
{
printf("(%.8f scriptlen.%d) ",dstr(msg->value),msg->pk_scriptlen);
int i; for (i=0; i<msg->pk_scriptlen; i++)
printf("%02x",msg->pk_script[i]);
printf("\n");
}
9 years ago
return(len);
}
int32_t iguana_rwjoinsplit(int32_t rwflag,uint8_t *serialized,struct iguana_msgjoinsplit *msg)
{
int32_t len = 0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->vpub_old),&msg->vpub_old);
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->vpub_new),&msg->vpub_new);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->anchor),msg->anchor.bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->nullifiers[0]),msg->nullifiers[0].bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->nullifiers[1]),msg->nullifiers[1].bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->commitments[0]),msg->commitments[0].bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->commitments[1]),msg->commitments[1].bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->ephemeralkey),msg->ephemeralkey.bytes);
if ( rwflag == 1 )
memcpy(&serialized[len],msg->ciphertexts,sizeof(msg->ciphertexts));
else memcpy(msg->ciphertexts,&serialized[len],sizeof(msg->ciphertexts));
len += sizeof(msg->ciphertexts);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->randomseed),msg->randomseed.bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->vmacs[0]),msg->vmacs[0].bytes);
len += iguana_rwbignum(rwflag,&serialized[len],sizeof(msg->vmacs[1]),msg->vmacs[1].bytes);
if ( rwflag == 1 )
memcpy(&serialized[len],msg->zkproof,sizeof(msg->zkproof));
else memcpy(msg->zkproof,&serialized[len],sizeof(msg->zkproof));
len += sizeof(msg->zkproof);
return(len);
}
8 years ago
int32_t iguana_rwtx(struct supernet_info *myinfo,uint8_t zcash,int32_t rwflag,struct iguana_info *coin,struct OS_memspace *mem,uint8_t *serialized,struct iguana_msgtx *msg,int32_t maxsize,bits256 *txidp,int32_t hastimestamp,int32_t isvpncoin)
9 years ago
{
8 years ago
int32_t i,n,len = 0; uint8_t *txstart = serialized; char txidstr[65];
9 years ago
if ( maxsize < sizeof(msg->version) )
return(-1);
8 years ago
msg->serialized = serialized;
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->version),&msg->version);
if ( hastimestamp != 0 )
9 years ago
{
if ( maxsize-len < sizeof(msg->timestamp) )
return(-1);
9 years ago
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->timestamp),&msg->timestamp);
9 years ago
}
9 years ago
len += iguana_rwvarint32(rwflag,&serialized[len],&msg->tx_in);
9 years ago
if ( rwflag == 0 )
msg->vins = iguana_memalloc(mem,msg->tx_in * sizeof(*msg->vins),1);
9 years ago
if ( maxsize-len <= 0 )
9 years ago
return(-1);
9 years ago
for (i=0; i<msg->tx_in; i++)
9 years ago
{
8 years ago
if ( len+sizeof(bits256)+sizeof(int32_t) > maxsize )
{
{
printf("invalid tx_in.%d len.%d vs maxsize.%d before\n",msg->tx_in,len,maxsize);
return(-1);
}
}
8 years ago
if ( (n= iguana_rwvin(rwflag,coin,mem,&serialized[len],&msg->vins[i],i)) >= 0 )
8 years ago
len += n;
if ( n < 0 || len+sizeof(int32_t) > maxsize )
9 years ago
{
printf("invalid tx_in.%d len.%d vs maxsize.%d\n",msg->tx_in,len,maxsize);
return(-1);
}
9 years ago
}
len += iguana_rwvarint32(rwflag,&serialized[len],&msg->tx_out);
8 years ago
if ( len + msg->tx_out*8 > maxsize )
8 years ago
{
printf("invalid tx_out.%d len.%d vs maxsize.%d\n",msg->tx_out,len,maxsize);
return(-1);
}
//printf("numvouts.%d ",msg->tx_out);
9 years ago
if ( rwflag == 0 )
msg->vouts = iguana_memalloc(mem,msg->tx_out * sizeof(*msg->vouts),1);
for (i=0; i<msg->tx_out; i++)
9 years ago
{
8 years ago
if ( (n= iguana_rwvout(rwflag,mem,&serialized[len],&msg->vouts[i])) > 0 )
8 years ago
len += n;
8 years ago
if ( n <= 0 || len > maxsize )
9 years ago
{
printf("invalid tx_out.%d len.%d vs maxsize.%d\n",msg->tx_out,len,maxsize);
return(-1);
}
9 years ago
}
len += iguana_rwnum(rwflag,&serialized[len],sizeof(msg->lock_time),&msg->lock_time);
9 years ago
if ( isvpncoin != 0 )
{
uint16_t ddosflag=0;
len += iguana_rwnum(rwflag,&serialized[len],sizeof(ddosflag),&ddosflag);
for (; serialized[len]!=0&&len<maxsize; len++) // eat null terminated string
;
}
if ( zcash != 0 && msg->version > 1 )
{
uint32_t numjoinsplits; struct iguana_msgjoinsplit joinsplit; uint8_t joinsplitpubkey[33],joinsplitsig[64];
len += iguana_rwvarint32(rwflag,&serialized[len],&numjoinsplits);
if ( numjoinsplits > 0 )
{
for (i=0; i<numjoinsplits; i++)
len += iguana_rwjoinsplit(rwflag,&serialized[len],&joinsplit);
if ( rwflag != 0 )
{
memset(joinsplitpubkey,0,sizeof(joinsplitpubkey)); // for now
memset(joinsplitsig,0,sizeof(joinsplitsig)); // set to actuals
memcpy(&serialized[len],joinsplitpubkey+1,32), len += 32;
memcpy(&serialized[len],joinsplitsig,64), len += 64;
}
else
{
joinsplitpubkey[0] = 0x02; // need to verify its not 0x03
memcpy(joinsplitpubkey+1,&serialized[len],32), len += 32;
memcpy(joinsplitsig,&serialized[len],64), len += 64;
}
}
if ( 0 )
{
*txidp = bits256_doublesha256(txidstr,txstart,len);
char str[65];
printf("[%ld] numjoinsplits.%d version.%d numvins.%d numvouts.%d locktime.%u %s\n",sizeof(joinsplit),numjoinsplits,msg->version,msg->tx_in,msg->tx_out,msg->lock_time,bits256_str(str,*txidp));
}
}
9 years ago
*txidp = bits256_doublesha256(txidstr,txstart,len);
msg->allocsize = len;
8 years ago
if ( coin->VALIDATENODE > 1 && rwflag == 0 && coin->RTheight > 0 )
8 years ago
{
int32_t sigsvalid; struct iguana_block *block;
if ( (block= iguana_blockfind("sig",coin,msg->txid)) != 0 && block->sigsvalid != 0 )
sigsvalid = 1;
else if ( iguana_validatesigs(myinfo,coin,txstart,len) == 0 )
sigsvalid = 1;
else
{
static FILE *fp;
if ( block != 0 )
block->sigsvalid = 1;
if ( fp == 0 )
fp = fopen("validates","wb");
if ( fp != 0 )
{
char str[65];
printf("error %s validating\n",bits256_str(str,*txidp));
for (i=0; i<len; i++)
{
printf("%02x",txstart[i]);
fprintf(fp,"%02x",txstart[i]);
}
printf(" len.%d\n\n",len);
fprintf(fp,"\n");
fflush(fp);
}
}
//return(0);
}
9 years ago
return(len);
}
8 years ago
char *iguana_txscan(struct supernet_info *myinfo,struct iguana_info *coin,cJSON *json,uint8_t *data,int32_t recvlen,bits256 txid)
{
struct iguana_msgtx tx; bits256 hash2; struct iguana_zblock *zblock; struct iguana_block *block; struct iguana_msgzblock zmsg; struct iguana_msgblock *msg = (void *)&zmsg;
8 years ago
int32_t i,n,len,txn_count,extralen = 65356; char *txbytes,vpnstr[64]; uint8_t *extraspace,blockspace[sizeof(*block)+sizeof(struct iguana_zblock)];
zblock = (void *)blockspace;
block = (void *)blockspace;
8 years ago
memset(&zmsg,0,sizeof(zmsg));
9 years ago
vpnstr[0] = 0;
9 years ago
extraspace = calloc(1,extralen);
8 years ago
if ( coin->chain->zcash == 0 )
{
8 years ago
len = iguana_rwblock(myinfo,coin->symbol,coin->chain->zcash,coin->chain->auxpow,coin->chain->hashalgo,0,&hash2,data,(void *)msg,recvlen);
iguana_blockconv(coin->chain->zcash,coin->chain->auxpow,(void *)block,(void *)msg,hash2,-1);
txn_count = msg->txn_count;
8 years ago
}
else
{
len = iguana_rwblock(myinfo,coin->symbol,coin->chain->zcash,coin->chain->auxpow,coin->chain->hashalgo,0,&hash2,data,(void *)&zmsg,recvlen);
iguana_blockconv(coin->chain->zcash,coin->chain->auxpow,zblock,&zmsg,hash2,-1);
txn_count = zmsg.txn_count;
8 years ago
}
for (i=0; i<txn_count; i++)
{
9 years ago
if ( (n= iguana_rwmsgtx(coin,coin->blocks.hwmchain.height,0,0,&data[len],recvlen - len,&tx,&tx.txid,vpnstr,extraspace,extralen,0,0)) < 0 )
break;
8 years ago
char str[65]; printf("%d of %d: %s len.%d\n",i,txn_count,bits256_str(str,tx.txid),len);
if ( bits256_cmp(txid,tx.txid) == 0 )
{
9 years ago
if ( (n= iguana_rwmsgtx(coin,coin->blocks.hwmchain.height,0,json,&data[len],recvlen - len,&tx,&tx.txid,vpnstr,extraspace,extralen,0,0)) > 0 )
{
txbytes = malloc(n*2+1);
init_hexbytes_noT(txbytes,&data[len],n);
9 years ago
free(extraspace);
return(txbytes);
}
}
len += n;
}
return(0);
}
8 years ago
int32_t iguana_gentxarray(struct supernet_info *myinfo,struct iguana_info *coin,struct OS_memspace *mem,struct iguana_txblock *txdata,int32_t *lenp,uint8_t *data,int32_t recvlen)
9 years ago
{
8 years ago
struct iguana_msgtx *tx; bits256 hash2; struct iguana_msgzblock zmsg; int32_t txn_count,i,n,hdrlen,len,numvouts,numvins; char str[65];
memset(&zmsg,0,sizeof(zmsg));
len = iguana_rwblock(myinfo,coin->symbol,coin->chain->zcash,coin->chain->auxpow,coin->chain->hashalgo,0,&hash2,data,(void *)&zmsg,recvlen);
9 years ago
hdrlen = len;
if ( len > recvlen )
{
printf("gentxarray error len.%d > recvlen.%d\n",len,recvlen);
9 years ago
return(-1);
}
8 years ago
txn_count = iguana_blockconv(coin->chain->zcash,coin->chain->auxpow,(void *)&txdata->zblock,&zmsg,hash2,-1);
numvins = numvouts = 0;
8 years ago
if ( txn_count > 0 )
9 years ago
{
8 years ago
tx = iguana_memalloc(mem,txn_count*sizeof(*tx),1);
for (i=0; i<txn_count; i++)
{
9 years ago
if ( len+32 > recvlen )
{
9 years ago
printf("gentxarrayB error len.%d > recvlen.%d\n",len,recvlen);
9 years ago
return(-1);
}
8 years ago
if ( (n= iguana_rwtx(myinfo,coin->chain->zcash,0,coin,mem,&data[len],&tx[i],recvlen - len,&tx[i].txid,coin->chain->isPoS,strcmp(coin->symbol,"VPN")==0)) < 0 )
{
8 years ago
//for (i=0; i<recvlen-hdrlen; i++)
// printf("%02x",data[hdrlen+i]);
9 years ago
printf(" <- gentxarrayC error i.%d len.%d > recvlen.%d, n.%d hdrlen.%d\n",i,len,recvlen,n,hdrlen);
9 years ago
return(-1);
}
numvouts += tx[i].tx_out;
numvins += tx[i].tx_in;
len += n;
}
if ( coin->chain->isPoS != 0 && len != recvlen && data[len] == (recvlen - len - 1) )
{
//printf("\n>>>>>>>>>>> len.%d vs recvlen.%d [%d]\n",len,recvlen,data[len]);
memcpy(txdata->space,&data[len],recvlen-len);
len += (recvlen-len);
txdata->extralen = (recvlen - len);
} else txdata->extralen = 0;
9 years ago
}
9 years ago
if ( coin->chain->auxpow != 0 && len != recvlen )
8 years ago
printf("numtx.%d %s hdrlen.%d len.%d vs recvlen.%d v.%08x\n",txn_count,bits256_str(str,hash2),hdrlen,len,recvlen,txdata->zblock.RO.version);
9 years ago
txdata->recvlen = len;
8 years ago
txdata->numtxids = txn_count;
9 years ago
txdata->numunspents = numvouts;
txdata->numspends = numvins;
return(len);
}
int32_t iguana_send_hashes(struct iguana_info *coin,char *command,struct iguana_peer *addr,bits256 stophash,bits256 *hashes,int32_t n)
{
uint32_t len,nVersion,varint; int32_t retval = -1; uint8_t *serialized; long size;
size = sizeof(struct iguana_msghdr) + sizeof(uint64_t) + 1 + sizeof(bits256)*(n+1);
if ( (varint= n) <= IGUANA_MAXINV )
{
serialized = mycalloc('h',1,size);
nVersion = 0;
len = iguana_rwblockhash(1,&serialized[sizeof(struct iguana_msghdr)],&nVersion,&varint,hashes,&stophash);
//printf("%s send_hashes.%d %s height.%d\n",addr->ipaddr,n,bits256_str(hashes[0]),iguana_height(coin,hashes[0]));
9 years ago
retval = iguana_queue_send(addr,0,serialized,command,len);
9 years ago
myfree(serialized,size);
} else printf("iguana_send_hashes: unexpected n.%d\n",n);
return(retval);
}
int32_t iguana_intvectors(struct iguana_info *coin,struct iguana_peer *addr,int32_t processflag,uint8_t *data,int32_t datalen) // other side needs to be a bit smart about what hashes are sents in
9 years ago
{
uint32_t type; bits256 *txids=0,*quotes=0,*blockhashes=0,hash; int32_t i,n,q,m,len; uint64_t x;
len = n = m = q = 0;
9 years ago
len += iguana_rwvarint(0,&data[len],&x);
for (i=0; i<x; i++)
{
len += iguana_rwnum(0,&data[len],sizeof(uint32_t),&type);
len += iguana_rwbignum(0,&data[len],sizeof(bits256),hash.bytes);
if ( type == MSG_TX )
{
if ( txids == 0 )
txids = mycalloc('t',(int32_t)x+1,sizeof(*txids));
txids[m++] = hash;
if ( (rand() % 1000) == 0 && i == x-1 )
printf("%s %d of %d: tx.%llx len.%d\n",addr->ipaddr,i,(int32_t)x,(long long)hash.txid,len);
}
else if ( type == MSG_BLOCK )
{
if ( blockhashes == 0 )
{
blockhashes = mycalloc('f',(int32_t)x+1,sizeof(*blockhashes));
n = 1;
}
blockhashes[n++] = hash;
}
9 years ago
/*else if ( type == MSG_QUOTE )
{
if ( quotes == 0 )
{
quotes = mycalloc('q',(int32_t)x+1,sizeof(*quotes));
q = 1;
}
quotes[q++] = hash;
9 years ago
}*/
9 years ago
else if ( type == MSG_FILTERED_BLOCK )
printf(" %d of %d: merkle.%llx\n",i,(int32_t)x,(long long)hash.txid);
else printf("what type is %d\n",type);
}
if ( n > 0 )
{
if ( n != x+1 )
{
printf("n.%d != x.%d -> realloc blockhashes\n",n,(int32_t)x+1);
blockhashes = myrealloc('f',blockhashes,(int32_t)((x+1)*sizeof(*blockhashes)),n*sizeof(*blockhashes));
} // else printf("n.%d == x.%d\n",n,(int32_t)x);
if ( processflag != 0 )
iguana_gotblockhashesM(coin,addr,blockhashes,n), blockhashes = 0;
}
if ( m > 0 )
{
if ( m != x )
txids = myrealloc('t',txids,(int32_t)((x+1)*sizeof(*txids)),(m+1)*sizeof(*txids));
if ( processflag != 0 )
iguana_gottxidsM(coin,addr,txids,m), txids = 0;
}
if ( q > 0 )
{
if ( q != x )
quotes = myrealloc('q',quotes,(int32_t)((x+1)*sizeof(*quotes)),(q+1)*sizeof(*quotes));
if ( processflag != 0 )
iguana_gotquotesM(coin,addr,quotes,q), quotes = 0;
}
9 years ago
if ( txids != 0 )
myfree(txids,sizeof(*txids) * (x+1));
if ( blockhashes != 0 )
myfree(blockhashes,sizeof(*blockhashes) * (x+1));
return(len);
//printf("intvectors.%c recvlen.%d\n",intvectors,recvlen);
}
8 years ago
int32_t iguana_msgparser(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,struct OS_memspace *rawmem,struct OS_memspace *txmem,struct OS_memspace *hashmem,struct iguana_msghdr *H,uint8_t *data,int32_t recvlen,int32_t fromcache)
9 years ago
{
8 years ago
uint8_t serialized[16384]; char *ipaddr; int32_t i,n=0,retval=-1,ishost,srvmsg,bloom,sendlen=0,intvectors,len= -100; uint64_t nonce,x; bits256 hash2;
9 years ago
bloom = intvectors = srvmsg = -1;
9 years ago
if ( strncmp(H->command+1,"uperNET",strlen("uperNET")) == 0 || strncmp(H->command,"uperNet",strlen("uperNet")) == 0 )
9 years ago
{
if ( addr != 0 )
{
9 years ago
if ( H->command[0] == 'S' )
addr->supernet = 1, addr->basilisk = 0;
else if ( H->command[0] == 's' )
addr->basilisk = 1, addr->supernet = 0;
9 years ago
ipaddr = addr->ipaddr;
} else ipaddr = 0;
len = recvlen;
9 years ago
//printf("GOT.(%s) len.%d from %s\n",H->command,recvlen,addr->ipaddr);
basilisk_p2p(myinfo,coin,addr,ipaddr,data,recvlen,&H->command[strlen("SuperNET")],H->command[6] == 'e' && H->command[7] == 't');
9 years ago
return(0);
}
9 years ago
if ( addr != 0 )
{
8 years ago
if ( 0 && addr->msgcounts.verack == 0 )
8 years ago
printf("iguana_msgparser verack.%d from (%s) parse.(%s) len.%d\n",addr->msgcounts.verack,addr->ipaddr,H->command,recvlen);
9 years ago
//iguana_peerblockrequest(coin,addr->blockspace,IGUANA_MAXPACKETSIZE,addr,iguana_blockhash(coin,100),0);
9 years ago
addr->lastcontact = (uint32_t)time(NULL);
strcpy(addr->lastcommand,H->command);
9 years ago
retval = 0;
if ( (ishost= (strcmp(H->command,"getblocks") == 0)) || strcmp(H->command,"block") == 0 )
9 years ago
{
9 years ago
if ( addr != 0 && rawmem->ptr != 0 )
{
9 years ago
struct iguana_txblock txdata;
iguana_memreset(rawmem), iguana_memreset(txmem);
memset(&txdata,0,sizeof(txdata));
if ( ishost == 0 )
9 years ago
{
8 years ago
if ( coin->chain->debug != 0 )
9 years ago
{
int32_t i,max;
max = coin->chain->zcash == 0 ? 80 : sizeof(struct iguana_msgzblockhdr);
for (i=0; i<max; i++)
9 years ago
printf("%02x",data[i]);
printf(" block.[%d]\n",max);
9 years ago
}
addr->msgcounts.block++;
8 years ago
if ( (n= iguana_gentxarray(myinfo,coin,rawmem,&txdata,&len,data,recvlen)) == recvlen || n == recvlen-1 )
9 years ago
{
len = n;
8 years ago
iguana_gotblockM(myinfo,coin,addr,&txdata,rawmem->ptr,H,data,recvlen,fromcache);
9 years ago
}
else
9 years ago
{
9 years ago
//for (i=0; i<recvlen; i++)
// printf("%02x",data[i]);
printf(" parse error block txn_count.%d, n.%d len.%d vs recvlen.%d from.(%s)\n",txdata.zblock.RO.txn_count,n,len,recvlen,addr->ipaddr);
9 years ago
}
}
9 years ago
else
{
9 years ago
len = iguana_peergetrequest(myinfo,coin,addr,data,recvlen,1);
9 years ago
//printf("peergetrequest len.%d\n",len);
9 years ago
}
9 years ago
} else printf("command.(%s) addr.%p rawmemptr.%p\n",H->command,addr,rawmem->ptr);
}
9 years ago
else if ( (ishost= (strncmp(H->command,"inv",3) == 0)) || strncmp(H->command,"getdata",7) == 0 )
{
9 years ago
if ( addr != 0 )
9 years ago
{
9 years ago
if ( ishost == 0 )
9 years ago
{
9 years ago
addr->msgcounts.getdata++;
len = iguana_peerdatarequest(coin,addr,data,recvlen);
9 years ago
}
9 years ago
else
{
9 years ago
intvectors = 'I', addr->msgcounts.inv++;
if ( 0 && strcmp(H->command,"inv2") == 0 )
printf("GOT INV2.%d\n",recvlen);
len = iguana_intvectors(coin,addr,1,data,recvlen); // indirectly issues getdata
9 years ago
}
9 years ago
}
9 years ago
}
9 years ago
else if ( (ishost= (strcmp(H->command,"getheaders") == 0)) || strcmp(H->command,"headers") == 0 )
9 years ago
{
8 years ago
struct iguana_msgzblock zmsg; struct iguana_msgblock *msg = (void *)&zmsg; struct iguana_zblock *zblocks; uint32_t tmp,n=0;
9 years ago
len = 0;
8 years ago
if ( addr != 0 && recvlen >= sizeof(bits256) && strcmp("NOTARY",coin->symbol) != 0 )
9 years ago
{
9 years ago
if ( ishost == 0 )
9 years ago
{
9 years ago
len = iguana_rwvarint32(0,data,&n);
if ( n <= IGUANA_MAXINV )
{
8 years ago
bits256 auxhash2,prevhash2; struct iguana_msgtx *tx; struct iguana_msgmerkle *coinbase_branch=0,*blockchain_branch=0; struct iguana_msgblock parentblock;
9 years ago
if ( rawmem->totalsize == 0 )
iguana_meminit(rawmem,"bighdrs",0,IGUANA_MAXPACKETSIZE * 2,0);
memset(prevhash2.bytes,0,sizeof(prevhash2));
8 years ago
zblocks = mycalloc('z',1,(int32_t)(sizeof(struct iguana_zblock) * n));
9 years ago
//printf("%s got %d headers len.%d\n",coin->symbol,n,recvlen);
for (i=0; i<n; i++)
9 years ago
{
9 years ago
if ( coin->chain->auxpow != 0 )
9 years ago
{
8 years ago
if ( coinbase_branch == 0 )
coinbase_branch = calloc(1,sizeof(*coinbase_branch));
if ( blockchain_branch == 0 )
blockchain_branch = calloc(1,sizeof(*blockchain_branch));
8 years ago
tmp = iguana_rwblockhdr(0,coin->chain->zcash,&data[len],(void *)msg);
9 years ago
hash2 = iguana_calcblockhash(coin->symbol,coin->chain->hashalgo,&data[len],tmp);
len += tmp;
8 years ago
if ( (msg->H.version & 0x100) != 0 )
9 years ago
{
iguana_memreset(rawmem);
tx = iguana_memalloc(rawmem,sizeof(*tx),1);
8 years ago
len += iguana_rwtx(myinfo,coin->chain->zcash,0,coin,rawmem,&data[len],tx,recvlen-len,&tx->txid,coin->chain->isPoS,strcmp(coin->symbol,"VPN")==0);
9 years ago
len += iguana_rwbignum(0,&data[len],sizeof(auxhash2),auxhash2.bytes);
len += iguana_rwmerklebranch(0,&data[len],coinbase_branch);
len += iguana_rwmerklebranch(0,&data[len],blockchain_branch);
len += iguana_rwblockhdr(0,coin->chain->zcash,&data[len],(void *)&parentblock);
9 years ago
}
len += iguana_rwvarint32(0,&data[len],&tmp);
char str[65],str2[65];
if ( 0 && coin->chain->auxpow != 0 )
8 years ago
printf("%d %d of %d: %s %s v.%08x numtx.%d cmp.%d\n",len,i,n,bits256_str(str,hash2),bits256_str(str2,zmsg.zH.prev_block),zmsg.zH.version,tmp,bits256_cmp(prevhash2,zmsg.zH.prev_block));
}
else len += iguana_rwblock(myinfo,coin->chain->symbol,coin->chain->zcash,coin->chain->auxpow,coin->chain->hashalgo,0,&hash2,&data[len],(void *)&zmsg,recvlen);
iguana_blockconv(coin->chain->zcash,coin->chain->auxpow,(void *)&zblocks[i],&zmsg,hash2,-1);
9 years ago
prevhash2 = hash2;
}
8 years ago
if ( coinbase_branch != 0 )
free(coinbase_branch);
if ( blockchain_branch != 0 )
free(blockchain_branch);
8 years ago
if ( iguana_gotheadersM(coin,addr,zblocks,n) < 0 )
myfree(zblocks,(int32_t)(sizeof(struct iguana_zblock) * n));
//myfree(blocks,sizeof(*blocks) * n);
9 years ago
if ( len == recvlen && addr != 0 )
addr->msgcounts.headers++;
} else printf("got unexpected n.%d for headers\n",n);
}
else if ( addr->headerserror == 0 )
8 years ago
{
9 years ago
len = iguana_peergetrequest(myinfo,coin,addr,data,recvlen,0);
8 years ago
}
9 years ago
}
9 years ago
}
9 years ago
else if ( (ishost= (strcmp(H->command,"version") == 0)) || strcmp(H->command,"verack") == 0 )
9 years ago
{
if ( addr != 0 )
{
9 years ago
if ( ishost != 0 )
{
9 years ago
struct iguana_msgversion recvmv;
len = iguana_rwversion(0,data,&recvmv,addr->ipaddr,recvlen);
if ( len <= recvlen )
9 years ago
iguana_gotversion(myinfo,coin,addr,&recvmv);
9 years ago
addr->msgcounts.version++;
9 years ago
}
else
{
9 years ago
iguana_gotverack(myinfo,coin,addr);
9 years ago
addr->msgcounts.verack++;
len = 0;
9 years ago
}
9 years ago
}
}
9 years ago
else if ( (ishost= (strcmp(H->command,"ping") == 0)) || strcmp(H->command,"pong") == 0 )
9 years ago
{
9 years ago
len = 0;
if ( recvlen == sizeof(uint64_t) && addr != 0 )
9 years ago
{
9 years ago
len = iguana_rwnum(0,data,sizeof(uint64_t),&nonce);
if ( addr != 0 )
9 years ago
{
9 years ago
//printf("%u got nonce.%llx from %s\n",(uint32_t)time(NULL),(long long)nonce,addr->ipaddr);
if ( ishost != 0 )
{
9 years ago
iguana_gotping(myinfo,coin,addr,nonce,data);
9 years ago
addr->msgcounts.ping++;
}
else
{
iguana_gotpong(coin,addr,nonce);
addr->msgcounts.pong++;
}
iguana_queue_send(addr,0,serialized,"getaddr",0);
9 years ago
}
9 years ago
}
9 years ago
}
else if ( (ishost= (strcmp(H->command,"getaddr") == 0)) || strcmp(H->command,"addr") == 0 )
{
struct iguana_msgaddress A;
//printf("iguana_msgparser from (%s) parse.(%s) len.%d\n",addr->ipaddr,H->command,recvlen);
if ( addr != 0 )
9 years ago
{
9 years ago
if ( ishost == 0 )
9 years ago
{
9 years ago
//for (i=0; i<recvlen; i++)
// printf("%02x",data[i]);
//printf(" addr recvlen.%d\n",recvlen);
len = iguana_rwvarint(0,data,&x);
for (i=0; i<x; i++)
9 years ago
{
9 years ago
memset(&A,0,sizeof(A));
len += iguana_rwaddr(0,&data[len],&A,CADDR_TIME_VERSION);//(int32_t)addr->protover);
iguana_gotaddr(coin,addr,&A);
}
if ( len == recvlen )
{
addr->lastgotaddr = (uint32_t)time(NULL);
addr->msgcounts.addr++;
}
}
else
{
len = 0;
if ( (sendlen= iguana_peeraddrrequest(coin,addr,&addr->blockspace[sizeof(H)],IGUANA_MAXPACKETSIZE)) > 0 )
{
if ( 0 )
9 years ago
{
9 years ago
int32_t checklen; uint32_t checkbits; char checkaddr[64];
checklen = iguana_rwvarint(0,&addr->blockspace[sizeof(H)],&x);
printf("\nSENDING:\n");
for (i=0; i<sendlen; i++)
printf("%02x",addr->blockspace[sizeof(H)+i]);
printf(" %p addr sendlen.%d N.%d\n",&addr->blockspace[sizeof(H)],sendlen,(int32_t)x);
for (i=0; i<x; i++)
{
memset(&A,0,sizeof(A));
checklen += iguana_rwaddr(0,&addr->blockspace[sizeof(H) + checklen],&A,CADDR_TIME_VERSION);
iguana_rwnum(0,&A.ip[12],sizeof(uint32_t),&checkbits);
expand_ipbits(checkaddr,checkbits);
printf("checkaddr.(%s:%02x%02x) ",checkaddr,((uint8_t *)&A.port)[1],((uint8_t *)&A.port)[0]);
}
printf("x.%d\n",(int32_t)x);
9 years ago
}
9 years ago
retval = iguana_queue_send(addr,0,addr->blockspace,"addr",sendlen);
9 years ago
}
9 years ago
addr->msgcounts.getaddr++;
9 years ago
}
9 years ago
}
9 years ago
//printf("%s -> addr recvlen.%d num.%d\n",addr->ipaddr,recvlen,(int32_t)x);
9 years ago
}
9 years ago
else if ( strcmp(H->command,"notfound") == 0 )
{
9 years ago
if ( addr != 0 )
{
printf("%s SERVER notfound\n",addr->ipaddr);
intvectors = 'N', addr->msgcounts.notfound++;
len = iguana_intvectors(coin,addr,1,data,recvlen);
}
}
9 years ago
else if ( strcmp(H->command,"mempool") == 0 )
{
9 years ago
if ( addr != 0 )
{
printf("%s SERVER mempool\n",addr->ipaddr);
srvmsg = 'M', addr->msgcounts.mempool++;
}
}
9 years ago
else if ( strcmp(H->command,"tx") == 0 )
{
9 years ago
struct iguana_msgtx *tx;
iguana_memreset(rawmem);
tx = iguana_memalloc(rawmem,sizeof(*tx),1);//mycalloc('u',1,sizeof(*tx));
8 years ago
len = iguana_rwtx(myinfo,coin->chain->zcash,0,coin,rawmem,data,tx,recvlen,&tx->txid,coin->chain->isPoS,strcmp(coin->symbol,"VPN")==0);
9 years ago
if ( addr != 0 )
{
iguana_gotunconfirmedM(coin,addr,tx,data,recvlen);
printf("tx recvlen.%d vs len.%d\n",recvlen,len);
addr->msgcounts.tx++;
}
}
9 years ago
else if ( addr != 0 && strcmp(H->command,"ConnectTo") == 0 )
{
iguana_queue_send(addr,0,serialized,"getaddr",0);
len = 6;
}
else if ( strcmp(H->command,"reject") == 0 )
9 years ago
{
9 years ago
if ( addr != 0 )
9 years ago
{
9 years ago
if ( strncmp((char *)data+1,"headers",7) == 0 )
addr->headerserror++;
else
{
8 years ago
for (i=0; i<recvlen&&i<100; i++)
9 years ago
printf("%02x ",data[i]);
8 years ago
printf("%s reject.(%s) recvlen.%d %s proto.%d\n",coin->symbol,data+1,recvlen,addr->ipaddr,addr->protover);
9 years ago
addr->msgcounts.reject++;
}
9 years ago
}
9 years ago
len = recvlen;
}
else if ( strcmp(H->command,"alert") == 0 )
{
struct iguana_msgalert alert;
memset(&alert,0,sizeof(alert));
len = iguana_rwmsgalert(coin,0,data,&alert);
if ( len == recvlen && addr != 0 )
addr->msgcounts.alert++;
}
else if ( addr != 0 )
{
if ( strcmp(H->command,"filterload") == 0 ) // for bloom
bloom = 'L', addr->msgcounts.filterload++;
else if ( strcmp(H->command,"filteradd") == 0 ) // for bloom
bloom = 'A', addr->msgcounts.filteradd++;
else if ( strcmp(H->command,"filterclear") == 0 ) // for bloom
bloom = 'C', addr->msgcounts.filterclear++;
else if ( strcmp(H->command,"merkleblock") == 0 ) // for bloom
bloom = 'M', addr->msgcounts.merkleblock++;
}
if ( bloom >= 0 || srvmsg >= 0 )
len = recvlen; // just mark as valid
if ( len != recvlen && len != recvlen-1 && len != recvlen-2 )
{
//printf("error.(%s) (%s): len.%d != recvlen.%d\n",H->command,addr->ipaddr,len,recvlen);
//for (i=0; i<len; i++)
// printf("%02x",data[i]);
8 years ago
if ( len != 0 && strcmp(H->command,"addr") != 0 && (coin->chain->auxpow == 0 || strcmp(H->command,"headers") != 0) )
9 years ago
printf("%s %s.%s len mismatch %d != %d\n",coin->symbol,addr!=0?addr->ipaddr:"local",H->command,len,recvlen);
}
8 years ago
else if ( len != recvlen && recvlen > 1 )
9 years ago
{
8 years ago
//printf("%s extra byte.[%02x] command.%s len.%d recvlen.%d\n",addr->ipaddr,data[recvlen-1],H->command,len,recvlen);
9 years ago
//retval = -1;
9 years ago
}
9 years ago
}
return(retval);
9 years ago
}