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.
 
 
 
 
 
 

390 lines
17 KiB

/******************************************************************************
* Copyright © 2014-2016 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#include "iguana777.h"
int32_t SuperNET_hexmsgfind(struct supernet_info *myinfo,bits256 category,bits256 subhash,char *hexmsg,int32_t addflag)
{
static int lastpurge; static uint64_t Packetcache[1024];
bits256 packethash; int32_t i,datalen;
datalen = (int32_t)strlen(hexmsg) + 1;
vcalc_sha256(0,packethash.bytes,(void *)hexmsg,datalen);
if ( bits256_nonz(category) == 0 )
category = GENESIS_PUBKEY;
if ( bits256_nonz(subhash) == 0 )
subhash = GENESIS_PUBKEY;
packethash = curve25519(category,packethash);
//printf("addflag.%d packethash.%llx dest.%llx\n",addflag,(long long)packethash.txid,(long long)category.txid);
for (i=0; i<sizeof(Packetcache)/sizeof(*Packetcache); i++)
{
if ( Packetcache[i] == 0 )
{
if ( addflag != 0 )
{
Packetcache[i] = packethash.txid;
//printf("add.%llx packetcache(%s) -> slot[%d]\n",(long long)packethash.txid,hexmsg,i);
}
break;
}
else if ( Packetcache[i] == packethash.txid )
{
//printf("SuperNET_DHTsend reject duplicate packet.%llx\n",(long long)packethash.txid);
return(i);
}
}
if ( i == sizeof(Packetcache)/sizeof(*Packetcache) )
{
if ( addflag != 0 )
{
printf("purge slot[%d]\n",lastpurge);
Packetcache[lastpurge++] = packethash.txid;
if ( lastpurge >= sizeof(Packetcache)/sizeof(*Packetcache) )
lastpurge = 0;
}
}
return(-1);
}
void SuperNET_hexmsgadd(struct supernet_info *myinfo,bits256 categoryhash,bits256 subhash,char *hexmsg,struct tai now,char *remoteaddr)
{
char str[512],str2[65];
str[0] = 0;
if ( memcmp(categoryhash.bytes,GENESIS_PUBKEY.bytes,sizeof(categoryhash)) == 0 )
strcpy(str,"BROADCAST.");
else bits256_str(str+strlen(str),categoryhash);
if ( memcmp(subhash.bytes,GENESIS_PUBKEY.bytes,sizeof(subhash)) != 0 )
{
bits256_str(str2,subhash);
strcat(str,str2);
}
category_posthexmsg(myinfo,categoryhash,subhash,hexmsg,now,remoteaddr);
//printf("HEXMSG.(%s).%llx -> %s\n",hexmsg,(long long)subhash.txid,str);
}
void SuperNET_hexmsgprocess(struct supernet_info *myinfo,cJSON *retjson,cJSON *json,char *hexmsg,char *remoteaddr)
{
int32_t len,flag=0; char *str; uint8_t _buf[8192],*buf = _buf; bits256 categoryhash,subhash; struct category_info *cat;
if ( hexmsg != 0 )
{
len = (int32_t)strlen(hexmsg);
if ( is_hexstr(hexmsg,len) > 0 )
{
len >>= 1;
if ( len > sizeof(_buf) )
buf = malloc(len);
decode_hex(buf,len,hexmsg);
categoryhash = jbits256(json,"categoryhash");
subhash = jbits256(json,"categoryhash");
if ( bits256_nonz(subhash) == 0 )
subhash = GENESIS_PUBKEY;
if ( (cat= category_find(categoryhash,subhash)) != 0 )
{
if ( cat->processfunc != 0 )
{
if ( (str= (*cat->processfunc)(myinfo,cat,buf,len,remoteaddr)) != 0 )
{
if ( retjson != 0 )
jaddstr(retjson,"processfunc",str);
else free(str);
}
flag = 1;
//printf("PROCESSFUNC\n");
}
}
if ( flag == 0 )
{
printf("no processfunc, posthexmsg\n");
category_posthexmsg(myinfo,categoryhash,jbits256(json,"subhash"),hexmsg,tai_now(),remoteaddr);
}
//char str[65]; printf("HEXPROCESS.(%s) -> %s\n",hexmsg,bits256_str(str,categoryhash));
if ( buf != _buf )
free(buf);
}
}
}
int32_t category_default_blockhash(struct category_chain *catchain,void *blockhashp,void *data,int32_t datalen)
{
bits256 hash;
vcalc_sha256(0,hash.bytes,data,datalen);
vcalc_sha256(0,blockhashp,hash.bytes,sizeof(hash));
return(sizeof(*blockhashp));
}
bits256 category_default_stake(struct category_chain *catchain,void *addr,int32_t addrlen)
{
bits256 stake;
memset(stake.bytes,0,sizeof(stake));
stake.txid = ((uint64_t)1 << 63);
return(stake);
}
bits256 catgory_default_hit(struct category_chain *catchain,int32_t height,void *prevgenerator,void *addr,void *blockhashp)
{
bits256 hash; bits256 rawhit,hit;
memset(rawhit.bytes,0,sizeof(rawhit));
memset(hit.bytes,0,sizeof(hit));
vcalc_sha256cat(hash.bytes,prevgenerator,catchain->addrlen,addr,catchain->addrlen);
hit = (*catchain->stake_func)(catchain,addr,catchain->addrlen);
rawhit.txid = hash.txid % ((uint64_t)1 << 42);
if ( rawhit.txid != 0 )
hit.txid /= rawhit.txid;
return(hit);
}
#define category_default_heaviest() (*catchain->default_func)(catchain,'H',0,0,0,0,zero)
#define category_default_latest() (*catchain->default_func)(catchain,'L',0,0,0,0,zero)
#define category_default_setheaviest(height,blockhashp,heaviest) (*catchain->default_func)(catchain,'S',height,0,0,blockhashp,zero)
#define category_default_weight(height) (*catchain->default_func)(catchain,'W',height,0,0,0,zero)
#define category_default_blockfind(height) (*catchain->default_func)(catchain,'B',height,0,0,0,zero)
bits256 category_default_func(struct category_chain *catchain,int32_t func,int32_t height,void *prevgenerator,void *addr,void *blockhashp,bits256 heaviest)
{
static const bits256 zero;
if ( catchain->hashlen != sizeof(bits256) || catchain->addrlen != sizeof(bits256) )
{
printf("unsupported hashlen.%d or addrlen.%d\n",catchain->hashlen,catchain->addrlen);
return(zero);
}
if ( height > catchain->maxblocknum + (func == 'S') )
{
printf("error func.%c setting heaviest. skipped %d -> %d?\n",func,catchain->maxblocknum,height);
return(catchain->category_hwm);
}
if ( func == 'H' )
return(catchain->category_hwm);
else if ( func == 'L' )
{
if ( catchain->maxblocknum < 0 )
return(catchain->genesishash);
else return(catchain->blocks[catchain->maxblocknum]);
}
else if ( func == 'S' )
{
catchain->category_hwm = heaviest;
if ( height > catchain->maxblocknum )
{
catchain->weights = realloc(catchain->weights,(catchain->maxblocknum+1) * sizeof(*catchain->weights));
catchain->blocks = realloc(catchain->blocks,(catchain->maxblocknum+1) * sizeof(*catchain->blocks));
}
catchain->maxblocknum = height;
catchain->weights[height] = heaviest;
if ( blockhashp != 0 )
memcpy(&catchain->blocks[height],blockhashp,sizeof(catchain->blocks[height]));
}
else if ( func == 'B' )
{
if ( height <= catchain->maxblocknum )
return(catchain->blocks[height]);
else
{
printf("error: illegal height.%d vs max.%d\n",height,catchain->maxblocknum);
return(zero);
}
}
else if ( func == 'W' )
{
if ( height >= 0 && height < catchain->maxblocknum )
return(catchain->weights[height]);
else printf("error getting weight for height.%d vs maxblocknum.%d\n",height,catchain->maxblocknum);
}
return(catchain->category_hwm);
}
int32_t category_default_ishwm(struct category_chain *catchain,int32_t prevheight,void *prevblockhashp,void *blockhashp,void *prevgenerator,void *addr)
{
bits256 checkhash,prevwt,oldhit,hit,heaviest; static const bits256 zero;
checkhash = category_default_blockfind(prevheight);
if ( memcmp(checkhash.bytes,prevblockhashp,catchain->hashlen) == 0 )
{
heaviest = category_default_heaviest();
prevwt = category_default_weight(prevheight);
oldhit = category_default_weight(prevheight+1);
hit = (*catchain->hit_func)(catchain,prevheight+1,prevgenerator,addr,blockhashp);
if ( hit.txid > oldhit.txid && prevwt.txid+hit.txid > heaviest.txid )
{
heaviest.txid = (prevwt.txid + hit.txid);
category_default_setheaviest(prevheight+1,blockhashp,heaviest);
return(prevheight+1);
}
} else return(-2);
return(-1);
}
int32_t category_default_payment(struct category_chain *catchain,void *src,void *dest,uint64_t amount)
{
//uint32_t srcind=0,destind=0;
// catchain->balances[destind] += amount;
// catchain->balances[srcind] -= amount;
return(0);
}
struct category_chain *category_chain_functions(struct supernet_info *myinfo,bits256 categoryhash,bits256 subhash,int32_t hashlen,int32_t addrlen,void *hash_func,void *stake_func,void *hit_func,void *default_func,void *ishwm_func,void *payment_func)
{
struct category_info *cat; struct category_chain *catchain = calloc(1,sizeof(*catchain));
if ( (cat= category_find(categoryhash,subhash)) != 0 )
{
catchain->maxblocknum = -1;
catchain->myinfo = myinfo, catchain->subinfo = cat->info;
if ( bits256_cmp(subhash,GENESIS_PUBKEY) == 0 )
catchain->categoryinfo = cat->info, catchain->genesishash = categoryhash;
else catchain->categoryinfo = category_find(categoryhash,GENESIS_PUBKEY), catchain->genesishash = subhash;
if ( catchain->myinfo == 0 || catchain->categoryinfo || catchain->subinfo )
{
printf("error with catchain pointers\n");
return(0);
}
if ( (catchain->addrlen= addrlen) <= 0 || (catchain->hashlen= hashlen) <= 0 )
{
printf("error with catchain lens.%d %d\n",addrlen,hashlen);
return(0);
}
if ( (catchain->blockhash_func= hash_func) == 0 || (catchain->stake_func= stake_func) == 0 || (catchain->hit_func= hit_func) == 0 || (catchain->default_func= default_func) == 0 || (catchain->ishwm_func= ishwm_func) == 0 || (catchain->payment_func= payment_func) == 0 )
{
if ( addrlen == sizeof(bits256) && hashlen == sizeof(bits256) )
{
catchain->blockhash_func = category_default_blockhash;
catchain->stake_func = category_default_stake;
catchain->hit_func = catgory_default_hit;
catchain->default_func = category_default_func;
catchain->ishwm_func = category_default_ishwm;
catchain->payment_func = category_default_payment;
}
else
{
printf("no category chain functions and addrlen.%d hashlen.%d not 32\n",addrlen,hashlen);
return(0);
}
}
cat->catchain = catchain;
return(catchain);
}
return(0);
}
struct crypto777_msghdr *crypto777_msgcreate(struct supernet_info *myinfo,struct crypto777_msghdr *msg,int32_t datalen)
{
bits256 otherpubkey; uint64_t signerbits; uint32_t timestamp; uint8_t buf[sizeof(msg->sig)],*data;
memset(&msg->sig,0,sizeof(msg->sig));
datalen += (int32_t)(sizeof(*msg) - sizeof(msg->sig));
data = (void *)((long)msg + sizeof(msg->sig));
otherpubkey = acct777_msgpubkey(data,datalen);
timestamp = (uint32_t)time(NULL);
acct777_sign(&msg->sig,myinfo->privkey,otherpubkey,timestamp,data,datalen);
if ( (signerbits= acct777_validate(&msg->sig,acct777_msgprivkey(data,datalen),msg->sig.pubkey)) != 0 )
{
//int32_t i;
//char str[65],str2[65];
//for (i=0; i<datalen; i++)
// printf("%02x",data[i]);
//printf(">>>>>>>>>>>>>>>> validated [%ld] len.%d (%s + %s)\n",(long)data-(long)msg,datalen,bits256_str(str,acct777_msgprivkey(data,datalen)),bits256_str(str2,msg->sig.pubkey));
memset(buf,0,sizeof(buf));
acct777_rwsig(1,buf,&msg->sig);
memcpy(&msg->sig,buf,sizeof(buf));
return(msg);
} else printf("error validating crypto777_msgcreate msg\n");
return(0);
}
void crypto777_catchain(struct supernet_info *myinfo,struct category_info *cat,bits256 *prevhashp,bits256 *btchashp)
{
*btchashp = myinfo->BTCmarkerhash;
*prevhashp = cat->catchain->hwmhash;
}
char *crypto777_sendmsg(struct supernet_info *myinfo,bits256 category,bits256 subhash,uint8_t *data,int32_t datalen,int32_t hops,char cmdstr[8])
{
char *hexstr,*retstr; int32_t i; struct crypto777_msghdr *msg; bits256 prevhash,btchash; struct category_info *cat;
msg = calloc(1,datalen + sizeof(*msg));
for (i=0; i<sizeof(msg->cmd); i++)
if ( (msg->cmd[i]= cmdstr[i]) == 0 )
break;
cat = category_info(category,subhash);
crypto777_catchain(myinfo,cat,&prevhash,&btchash);
iguana_rwbignum(1,msg->prevhash.bytes,sizeof(bits256),prevhash.bytes);
iguana_rwbignum(1,msg->btchash.bytes,sizeof(bits256),btchash.bytes);
memcpy(msg->serialized,data,datalen);
if ( crypto777_msgcreate(myinfo,msg,datalen) != 0 )
{
printf(">>>>>>>>>>>> crypto777_send.(%s) datalen.%d allocsize.%d crc.%x\n",cmdstr,datalen,msg->sig.allocsize,calc_crc32(0,(void *)((long)msg + 8),datalen-8));
hexstr = malloc(msg->sig.allocsize*2 + 1);
init_hexbytes_noT(hexstr,(uint8_t *)msg,msg->sig.allocsize);
retstr = SuperNET_categorymulticast(myinfo,0,category,subhash,hexstr,0,hops,1,0,0);
free(hexstr), free(msg);
return(retstr);
}
else
{
free(msg);
printf("cant crypto777 msgcreate datalen.%d\n",datalen);
return(clonestr("{\"error\":\"couldnt create crypto777 message\"}"));
}
}
char *crypto777_hexmsg(struct supernet_info *myinfo,void *ptr,int32_t len,char *remoteaddr)
{
struct crypto777_msghdr *msg = ptr; int32_t slen,datalen,newlen,flag = 0; bits256 prevhash,btchash;
uint8_t *serdata; uint64_t signerbits; uint8_t tmp[sizeof(msg->sig)]; cJSON *argjson = 0;
datalen = len - (int32_t)sizeof(msg->sig);
serdata = (void *)((long)msg + sizeof(msg->sig));
acct777_rwsig(0,(void *)&msg->sig,(void *)tmp);
memcpy(&msg->sig,tmp,sizeof(msg->sig));
/*if ( remoteaddr != 0 && remoteaddr[0] == 0 && strcmp("127.0.0.1",remoteaddr) == 0 && ((uint8_t *)msg)[len-1] == 0 && (argjson= cJSON_Parse((char *)msg)) != 0 )
{
printf("string crypto777_hexmsg RESULT.(%s)\n",jprint(argjson,0));
free_json(argjson);
return(clonestr("{\"error\":\"string base packets deprecated\"}"));
}
else*/ if ( (signerbits= acct777_validate(&msg->sig,acct777_msgprivkey(serdata,datalen),msg->sig.pubkey)) != 0 )
{
flag++;
iguana_rwbignum(0,msg->prevhash.bytes,sizeof(bits256),prevhash.bytes);
iguana_rwbignum(0,msg->btchash.bytes,sizeof(bits256),btchash.bytes);
printf("crypto777_hexmsg <<<<<<<<<<<<< sigsize.%ld VALIDATED [%ld] len.%d t%u allocsize.%d (%s) [%d]\n",sizeof(msg->sig),(long)serdata-(long)msg,datalen,msg->sig.timestamp,msg->sig.allocsize,(char *)msg->serialized,serdata[datalen-1]);
newlen = (int32_t)(msg->sig.allocsize - ((long)msg->serialized - (long)msg));
serdata = msg->serialized;
if ( (argjson= cJSON_Parse((char *)serdata)) != 0 )
{
slen = (int32_t)strlen((char *)serdata) + 1;
serdata = &serdata[slen];
newlen -= slen;
free_json(argjson);
}
}
return(clonestr("{\"result\":\"test packet\"}"));
}
/*
Consensus rules:
0. Valid burn protocol or new issuance with small fee to crypto777 account -> OP_RETURN on BTCD with txid of payment/burn
Ti boundary - Balances reconciled and signed by issuer or super majority vote. Only amounts marked as frozen eligible for atomic swaps.
tx via p2p, signed payment to dest acct, based on balance. no outputs to double spend
payment valid during Ti and Ti+1
atomic cross chain: both sides freeze trade amount, wait for this to be confirmed in BTC OP_RETURN, then a joint swap tx is signed by both and submitted to both chains
valid tx must be accepted and sig added with Ti slippage. It is valid if signed, and balance is available.
When Ti boundary changes, all online nodes reconcile the submitted tx to make sure all are confirmed and balances updated. Special tx like freezing, atomics, etc.
Top PoS account publishes balance changes and majority stake approves. Next trade period starts at Ti+2
Split into odd/even offset periods to allow nonstop tx
1. all nodes must ntp and all tx must be timestamped within 50 seconds in the past and cant be more than 10 seconds from the future.
2. tx spends cannot exceed available balance/2 as of prior Ti.
2. all tx must refer to the latest BTC.Ti and BTCD.Ti and BTC.RTblock. any tx received that has older BTC.Ti is rejected.
3.
*/