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.
 
 
 
 
 
 

12841 lines
573 KiB

//
// obsolete.h
// pnacl
//
// Created by jimbo laptop on 10/27/15.
// Copyright (c) 2015 jl777. All rights reserved.
//
#ifndef pnacl_obsolete_h
#define pnacl_obsolete_h
if ( 0 )
{
sleep(3);
char *str,*jsonstr = clonestr("{\"plugin\":\"relay\",\"method\":\"busdata\"}"); uint32_t nonce;
if ( (str= busdata_sync(&nonce,jsonstr,"allnodes",0)) != 0 )
{
fprintf(stderr,"busdata.(%s)\n",str);
free(str);
} else printf("null return from busdata sync.(%s)\n",jsonstr);
getchar();exit(1);
}
int32_t nn_stripctrl(int32_t *clenp,uint8_t *ctrl,int32_t ctrlsize,uint8_t *buf)
{
int32_t clen,offset;
offset = 1;
if ( (clen= buf[0]) > 0 )
{
if ( clen == 0xfd )
{
clen = buf[1] | (buf[2] << 8);
offset += 2;
}
printf("nn_stripctrl: clen.%d offset.%d\n",clen,offset);
if ( clen > ctrlsize )
{
printf("too much control data.%d vs %d, truncate\n",clen,(int32_t)sizeof(ctrl));
memcpy(ctrl,&buf[offset],ctrlsize);
*clenp = ctrlsize;
errno = MSG_CTRUNC;
}
else
{
memcpy(ctrl,&buf[offset],clen);
*clenp = clen;
}
//printf("copied (%d).%d bytes of control from nbytes.%d\n",clen,offset-clen,(int32_t)nbytes);
} else *clenp = 0;
offset += clen;
return(offset);
}
static bool nc_conn_ip_active(struct net_child_info *nci,const unsigned char *ip)
{
unsigned int i;
for (i = 0; i < nci->conns->len; i++)
{
struct nc_conn *conn;
conn = parr_idx(nci->conns, i);
if (!memcmp(conn->peer.addr.ip, ip, 16))
return true;
}
return false;
}
static bool nc_conn_group_active(struct net_child_info *nci,const struct peer *peer)
{
// FIXME
return false;
unsigned int group_len = peer->group_len;
unsigned int i;
for (i = 0; i < nci->conns->len; i++)
{
struct nc_conn *conn;
conn = parr_idx(nci->conns, i);
if ((group_len == conn->peer.group_len) && !memcmp(peer->group, conn->peer.group, group_len))
return true;
}
return false;
}
static struct nc_conn *nc_conn_new(const struct peer *peer)
{
struct nc_conn *conn;
conn = calloc(1, sizeof(*conn));
if (!conn)
return NULL;
conn->fd = -1;
peer_copy(&conn->peer, peer);
bn_address_str(conn->addr_str, sizeof(conn->addr_str), conn->peer.addr.ip);
return conn;
}
static void nc_conn_kill(struct net_child_info *nci,struct nc_conn *conn)
{
assert(conn->dead == false);
conn->dead = true;
event_base_loopbreak(conn->nci->eb);
}
static void nc_conn_free(struct net_child_info *nci,struct nc_conn *conn)
{
if (!conn)
return;
if (conn->write_q)
{
clist *tmp = conn->write_q;
while (tmp)
{
struct buffer *buf;
buf = tmp->data;
tmp = tmp->next;
free(buf->p);
free(buf);
}
clist_free(conn->write_q);
}
if (conn->ev)
{
event_del(conn->ev);
event_free(conn->ev);
}
if (conn->write_ev)
{
event_del(conn->write_ev);
event_free(conn->write_ev);
}
if (conn->fd >= 0)
close(conn->fd);
free(conn->msg.data);
memset(conn, 0, sizeof(*conn));
free(conn);
}
static bool nc_conn_start(struct net_child_info *nci,struct nc_conn *conn)
{
char errpfx[64];
/* create socket */
printf("start connection.(%s)\n",conn->addr_str);
conn->ipv4 = is_ipv4_mapped(conn->peer.addr.ip);
conn->fd = socket(conn->ipv4 ? AF_INET : AF_INET6,SOCK_STREAM,IPPROTO_TCP);
if ( conn->fd < 0 )
{
sprintf(errpfx, "socket %s", conn->addr_str);
perror(errpfx);
return false;
}
/* set non-blocking */
int flags = fcntl(conn->fd,F_GETFL,0);
if ( (flags < 0) || (fcntl(conn->fd,F_SETFL,flags | O_NONBLOCK) < 0) )
{
sprintf(errpfx, "socket fcntl %s", conn->addr_str);
perror(errpfx);
return false;
}
struct sockaddr *saddr;
struct sockaddr_in6 saddr6;
struct sockaddr_in saddr4;
socklen_t saddr_len;
/* fill out connect(2) address */
if (conn->ipv4)
{
memset(&saddr4, 0, sizeof(saddr4));
saddr4.sin_family = AF_INET;
memcpy(&saddr4.sin_addr.s_addr,&conn->peer.addr.ip[12],4);
saddr4.sin_port = htons(conn->peer.addr.port);
saddr = (struct sockaddr *) &saddr4;
saddr_len = sizeof(saddr4);
}
else
{
memset(&saddr6, 0, sizeof(saddr6));
saddr6.sin6_family = AF_INET6;
memcpy(&saddr6.sin6_addr.s6_addr,&conn->peer.addr.ip[0], 16);
saddr6.sin6_port = htons(conn->peer.addr.port);
saddr = (struct sockaddr *) &saddr6;
saddr_len = sizeof(saddr6);
}
// initiate TCP connection
if ( connect(conn->fd,saddr,saddr_len) < 0 )
{
if ( errno != EINPROGRESS )
{
sprintf(errpfx, "socket connect %s", conn->addr_str);
perror(errpfx);
return false;
}
}
return true;
}
static bool nc_conn_got_header(struct net_child_info *nci,struct nc_conn *conn)
{
parse_message_hdr(&conn->msg.hdr, conn->hdrbuf);
unsigned int data_len = conn->msg.hdr.data_len;
if (data_len > (16 * 1024 * 1024))
{
free(conn->msg.data);
conn->msg.data = NULL;
return false;
}
conn->msg.data = malloc(data_len);
/* switch to read-body state */
conn->msg_p = conn->msg.data;
conn->expected = data_len;
conn->reading_hdr = false;
return true;
}
static bool nc_conn_got_msg(struct net_child_info *nci,struct nc_conn *conn)
{
if (!message_valid(&conn->msg)) {
fprintf(nci->plog, "llnet: %s invalid message\n",conn->addr_str);
return false;
}
if (!nc_conn_message(nci,conn))
return false;
free(conn->msg.data);
conn->msg.data = NULL;
/* switch to read-header state */
conn->msg_p = conn->hdrbuf;
conn->expected = P2P_HDR_SZ;
conn->reading_hdr = true;
return true;
}
static void nc_conn_read_evt(int fd, short events, void *priv)
{
struct nc_conn *conn = priv;
struct net_child_info *nci = conn->nci;
ssize_t rrc = read(fd, conn->msg_p, conn->expected);
if (rrc <= 0)
{
if (rrc < 0)
fprintf(nci->plog, "llnet: %s read: %s\n",conn->addr_str,strerror(errno));
else fprintf(nci->plog, "llnet: %s read EOF\n", conn->addr_str);
goto err_out;
}
conn->msg_p += rrc;
conn->expected -= rrc;
/* execute our state machine at most twice */
unsigned int i;
for (i = 0; i < 2; i++)
{
if (conn->expected == 0)
{
if (conn->reading_hdr)
{
if (!nc_conn_got_header(nci,conn))
goto err_out;
}
else
{
if (!nc_conn_got_msg(nci,conn))
goto err_out;
}
}
}
return;
err_out:
nc_conn_kill(nci,conn);
}
static cstring *nc_version_build(struct net_child_info *nci)
{
struct msg_version mv;
msg_version_init(&mv);
mv.nVersion = PROTO_VERSION;
mv.nServices = nci->blocks_fp != 0 ? NODE_NETWORK : 0;
mv.nTime = (int64_t)time(NULL);
mv.nonce = nci->instance_nonce;
sprintf(mv.strSubVer,"/nano/");
mv.nStartingHeight = nci->db.best_chain ? nci->db.best_chain->height : 0;
cstring *rs = ser_msg_version(&mv);
msg_version_free(&mv);
return rs;
}
static bool nc_conn_read_enable(struct net_child_info *nci,struct nc_conn *conn)
{
if (conn->ev)
return true;
conn->ev = event_new(conn->nci->eb, conn->fd, EV_READ | EV_PERSIST,(void *)nc_conn_read_evt, conn);
if (!conn->ev)
return false;
if (event_add(conn->ev, NULL) != 0)
{
event_free(conn->ev);
conn->ev = NULL;
return false;
}
return true;
}
static bool nc_conn_read_disable(struct net_child_info *nci,struct nc_conn *conn)
{
if (!conn->ev)
return true;
event_del(conn->ev);
event_free(conn->ev);
conn->ev = NULL;
return true;
}
static bool nc_conn_write_enable(struct net_child_info *nci,struct nc_conn *conn)
{
if (conn->write_ev)
return true;
conn->write_ev = event_new(conn->nci->eb, conn->fd,EV_WRITE | EV_PERSIST,(void *)nc_conn_write_evt, conn);
if (!conn->write_ev)
return false;
if (event_add(conn->write_ev, NULL) != 0)
{
event_free(conn->write_ev);
conn->write_ev = NULL;
return false;
}
return true;
}
static bool nc_conn_write_disable(struct net_child_info *nci,struct nc_conn *conn)
{
if (!conn->write_ev)
return true;
event_del(conn->write_ev);
event_free(conn->write_ev);
conn->write_ev = NULL;
return true;
}
static void nc_conn_evt_connected(int fd, short events, void *priv)
{
struct nc_conn *conn = priv;
struct net_child_info *nci = conn->nci;
if ((events & EV_WRITE) == 0) {
fprintf(nci->plog, "net: %s connection timeout\n", conn->addr_str);
goto err_out;
}
int err = 0;
socklen_t len = sizeof(err);
/* check success of connect(2) */
if ((getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) || (err != 0))
{
fprintf(nci->plog, "net: connect %s failed: %s\n",conn->addr_str, strerror(err));
goto err_out;
}
if (nci->debugging)
fprintf(nci->plog, "net: connected to %s\n", conn->addr_str);
conn->connected = true;
/* clear event used for watching connect(2) */
event_free(conn->ev);
conn->ev = NULL;
/* build and send "version" message */
cstring *msg_data = nc_version_build(nci);
bool rc = nc_conn_send(nci,conn, "version", msg_data->str, msg_data->len);
cstr_free(msg_data, true);
if (!rc)
{
fprintf(nci->plog, "net: %s !conn_send\n", conn->addr_str);
goto err_out;
}
/* switch to read-header state */
conn->msg_p = conn->hdrbuf;
conn->expected = P2P_HDR_SZ;
conn->reading_hdr = true;
if (!nc_conn_read_enable(nci,conn))
{
fprintf(nci->plog, "net: %s read not enabled\n", conn->addr_str);
goto err_out;
}
return;
err_out:
nc_conn_kill(nci,conn);
}
static void nc_conns_gc(struct net_child_info *nci, bool free_all)
{
clist *dead = NULL;
unsigned int n_gc = 0;
/* build list of dead connections */
unsigned int i;
for (i = 0; i < nci->conns->len; i++)
{
struct nc_conn *conn = parr_idx(nci->conns, i);
if (free_all || conn->dead)
dead = clist_prepend(dead, conn);
}
/* remove and free dead connections */
clist *tmp = dead;
while (tmp)
{
struct nc_conn *conn = tmp->data;
tmp = tmp->next;
parr_remove(nci->conns, conn);
nc_conn_free(nci,conn);
n_gc++;
}
clist_free(dead);
if (nci->debugging)
fprintf(nci->plog, "net: gc'd %u connections\n", n_gc);
}
static void nc_conns_open(struct net_child_info *nci)
{
if (nci->debugging)
fprintf(nci->plog, "net: open connections (have %zu, want %zu more)\n",nci->conns->len,NC_MAX_CONN - nci->conns->len);
printf("nc_conns_open\n");
while ((bp_hashtab_size(nci->peers->map_addr) > 0) && (nci->conns->len < NC_MAX_CONN))
{
// delete peer from front of address list. it will be re-added before writing peer file, if successful
struct peer *peer = peerman_pop(nci->peers);
struct nc_conn *conn = nc_conn_new(peer);
conn->nci = nci;
peer_free(peer);
free(peer);
fprintf(stderr, "net: connecting to [%s]\n",conn->addr_str);
if (nc_conn_ip_active(nci, conn->peer.addr.ip)) // are we already connected to this IP?
{
fprintf(nci->plog, "net: already connected to %s\n",conn->addr_str);
goto err_loop;
}
if (nc_conn_group_active(nci, &conn->peer)) // are we already connected to this network group?
{
fprintf(nci->plog, "net: already grouped to %s\n",conn->addr_str);
goto err_loop;
}
if (!nc_conn_start(nci,conn)) // initiate non-blocking connect(2)
{
fprintf(nci->plog, "net: failed to start connection to %s\n",conn->addr_str);
goto err_loop;
}
// add to our list of monitored event sources
conn->ev = event_new(nci->eb, conn->fd, EV_WRITE,(void *)nc_conn_evt_connected, conn);
if ( !conn->ev )
{
fprintf(nci->plog, "net: event_new failed on %s\n",conn->addr_str);
goto err_loop;
}
struct timeval timeout = { net_conn_timeout, };
if (event_add(conn->ev, &timeout) != 0)
{
fprintf(nci->plog, "net: event_add failed on %s\n",conn->addr_str);
goto err_loop;
}
parr_add(nci->conns, conn); // add to our list of active connections
continue;
err_loop:
nc_conn_kill(nci,conn);
}
}
static void nc_conns_process(struct net_child_info *nci)
{
nc_conns_gc(nci, false);
nc_conns_open(nci);
}
static bool parse_kvstr(const char *s, char **key, char **value)
{
char *eql;
eql = strchr(s, '=');
if (eql)
{
uint32_t keylen = (uint32_t)((long)eql - (long)s);
*key = strndup(s, keylen);
*value = strdup(s + keylen + 1);
}
else
{
*key = strdup(s);
*value = strdup("");
}
/* blank keys forbidden; blank values permitted */
if (!strlen(*key))
{
free(*key);
free(*value);
*key = NULL;
*value = NULL;
return false;
}
return true;
}
static bool read_config_file(struct net_child_info *nci,const char *cfg_fn)
{
FILE *cfg = fopen(cfg_fn, "r");
if (!cfg)
return false;
bool rc = false;
char line[1024];
while (fgets(line, sizeof(line), cfg) != NULL)
{
char *key, *value;
if (line[0] == '#')
continue;
while (line[0] && (isspace(line[strlen(line) - 1])))
line[strlen(line) - 1] = 0;
if (!parse_kvstr(line, &key, &value))
continue;
bp_hashtab_put(nci->settings, key, value);
}
rc = ferror(cfg) == 0;
fclose(cfg);
return rc;
}
static bool do_setting(struct net_child_info *nci,const char *arg)
{
char *key, *value;
if (!parse_kvstr(arg, &key, &value))
return false;
bp_hashtab_put(nci->settings, key, value);
// trigger special setting-specific behaviors
if (!strcmp(key, "debug"))
nci->debugging = true;
else if (!strcmp(key, "config") || !strcmp(key, "c"))
return read_config_file(nci,value);
return true;
}
static bool preload_settings(struct net_child_info *nci)
{
unsigned int i;
/* preload static settings */
for (i = 0; i < ARRAY_SIZE(const_settings); i++)
if (!do_setting(nci,const_settings[i]))
return false;
return true;
}
/*unsigned int arg;
for (arg = 1; arg < argc; arg++)
{
const char *argstr = argv[arg];
if ( do_setting(nci,argstr) == 0 )
return 1;
}*/
/*
* properly capture TERM and other signals
*/
static void nc_conn_write_evt(int fd, short events, void *priv)
{
struct nc_conn *conn = priv;
struct iovec *iov = NULL;
unsigned int iov_len = 0;
struct net_child_info *nci = conn->nci;
/* build list of outgoing data buffers */
nc_conn_build_iov(conn->write_q, conn->write_partial, &iov, &iov_len);
printf("send data to network\n");
/* send data to network */
ssize_t wrc = mywritev(conn->fd, iov, iov_len);
free(iov);
if (wrc < 0)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
goto err_out;
return;
}
/* handle partially and fully completed buffers */
nc_conn_written(conn, wrc);
/* thaw read, if write fully drained */
if (!conn->write_q)
{
nc_conn_write_disable(nci,conn);
nc_conn_read_enable(nci,conn);
}
return;
err_out:
nc_conn_kill(nci,conn);
}
static void nc_conn_build_iov(clist *write_q, unsigned int partial,struct iovec **iov_, unsigned int *iov_len_)
{
*iov_ = NULL;
*iov_len_ = 0;
unsigned int i, iov_len = (uint32_t)clist_length(write_q);
struct iovec *iov = calloc(iov_len, sizeof(struct iovec));
clist *tmp = write_q;
i = 0;
while (tmp)
{
struct buffer *buf = tmp->data;
iov[i].iov_base = buf->p;
iov[i].iov_len = buf->len;
if (i == 0)
{
iov[0].iov_base += partial;
iov[0].iov_len -= partial;
}
tmp = tmp->next;
i++;
}
*iov_ = iov;
*iov_len_ = iov_len;
}
static void nc_conn_written(struct nc_conn *conn, size_t bytes)
{
while (bytes > 0)
{
clist *tmp;
struct buffer *buf;
uint32_t left;
tmp = conn->write_q;
buf = tmp->data;
left = (uint32_t)(buf->len - conn->write_partial);
/* buffer fully written; free */
if (bytes >= left)
{
free(buf->p);
free(buf);
conn->write_partial = 0;
conn->write_q = clist_delete(tmp, tmp);
bytes -= left;
}
/* buffer partially written; store state */
else
{
conn->write_partial += bytes;
break;
}
}
}
ssize_t mywritev(int fildes, const struct iovec *iov, int iovcnt)
{
int i;
int32_t bytes_written = 0;
for (i = 0; i < iovcnt; i++)
{
int len = (int32_t)send(fildes,iov[i].iov_base,iov[i].iov_len,0);
if (len < 0)
{
//DWORD err = GetLastError();
//errno = ewin_to_posix_error(err);
bytes_written = -1;
break;
}
bytes_written += len;
}
return bytes_written;
}
static bool nc_msg_version(struct net_child_info *nci,struct nc_conn *conn)
{
if (conn->seen_version)
return false;
conn->seen_version = true;
struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len };
struct msg_version mv;
bool rc = false;
msg_version_init(&mv);
if (!deser_msg_version(&mv, &buf))
goto out;
if (nci->debugging)
{
char fromstr[64], tostr[64];
bn_address_str(fromstr, sizeof(fromstr), mv.addrFrom.ip);
bn_address_str(tostr, sizeof(tostr), mv.addrTo.ip);
fprintf(nci->plog, "net: %s version(%u, 0x%llx, %lld, To:%s, From:%s, %s, %u)\n",
conn->addr_str,
mv.nVersion,
(unsigned long long) mv.nServices,
(long long) mv.nTime,
tostr,
fromstr,
mv.strSubVer,
mv.nStartingHeight);
}
if (!(mv.nServices & NODE_NETWORK)) /* require NODE_NETWORK */
goto out;
if (mv.nonce == nci->instance_nonce) /* connected to ourselves? */
goto out;
conn->protover = (mv.nVersion < PROTO_VERSION) ? mv.nVersion : PROTO_VERSION;
/* acknowledge version receipt */
if (!nc_conn_send(nci,conn, "verack", NULL, 0))
goto out;
rc = true;
out:
msg_version_free(&mv);
return rc;
}
static bool nc_conn_send(struct net_child_info *nci,struct nc_conn *conn, const char *command,const void *data, size_t data_len)
{
/* build wire message */
cstring *msg = message_str(nci->chain->netmagic, command, data, (uint32_t)data_len);
if (!msg)
return false;
/* buffer now owns message data */
struct buffer *buf = calloc(1, sizeof(struct buffer));
buf->p = msg->str;
buf->len = msg->len;
cstr_free(msg, false);
/* if write q exists, write_evt will handle output */
if (conn->write_q)
{
conn->write_q = clist_append(conn->write_q, buf);
return true;
}
/* attempt optimistic write */
ssize_t wrc = write(conn->fd, buf->p, buf->len);
if (wrc < 0)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
free(buf->p);
free(buf);
return false;
}
conn->write_q = clist_append(conn->write_q, buf);
goto out_wrstart;
}
/* message fully sent */
if (wrc == buf->len)
{
free(buf->p);
free(buf);
return true;
}
/* message partially sent; pause read; poll for writable */
conn->write_q = clist_append(conn->write_q, buf);
conn->write_partial = (uint32_t)wrc;
out_wrstart:
nc_conn_read_disable(nci,conn);
nc_conn_write_enable(nci,conn);
return true;
}
static void init_daemon(struct net_child_info *nci,char *coin)
{
strcpy(nci->coin,coin);
//init_log(nci);
//init_blkdb(nci);
//printf("utxo\n");
//bp_utxo_set_init(&nci->uset);
//printf("init_blocks\n");
//init_blocks(nci);
//printf("init_orphans\n");
init_orphans(nci);
//readprep_blocks_file(nci);
init_nci(nci);
}
int32_t iguana_verack(struct net_child_info *nci,struct bp_address *addr)
{
struct msg_getblocks gb; int32_t rc,numsent; time_t now,cutoff; cstring *s,*msg;
if ( addr->seen_verack )
{
printf("addr->seen_verack %d\n",addr->seen_verack);
return(-1);
}
addr->seen_verack = 1;
addr->nTime = (uint32_t)time(NULL);
addr->n_ok++;
//peerman_add(conn->nci->peers, &conn->peer,true);
if ( addr->protover >= CADDR_TIME_VERSION )
{
msg = message_str(nci->chain->netmagic,"getaddr",NULL,0);
if ( (numsent= (int32_t)send(addr->usock,msg->str,msg->len,0)) != msg->len )
{
cstr_free(msg,true);
return -1;
}
cstr_free(msg,true);
} else printf("protover.%d vs %d CADDR_TIME_VERSION\n",addr->protover,CADDR_TIME_VERSION);
rc = 0;
now = time(NULL);
cutoff = now - (24 * 60 * 60);
if ( nci->last_getblocks < cutoff )
{
msg_getblocks_init(&gb);
blkdb_locator(&nci->db,NULL,&gb.locator);
s = ser_msg_getblocks(&gb);
oldsend_getblocks(nci);
msg = message_str(nci->chain->netmagic,"getblocks",s->str,(uint32_t)s->len);
cstr_free(s,true);
msg_getblocks_free(&gb);
nci->last_getblocks = now;
}
return(rc);
}
static void init_peers(struct net_child_info *nci)
{
struct peer_manager *peers = 0;
peers = peerman_read(setting(nci,"peers"));
printf("init_peers.%p\n",peers);
if (!peers)
{
PostMessage( "net: initializing empty peer list\n");
peers = peerman_seed(nci->chain->default_port,1,1);//setting(nci,"dns") != 0 ? true : false,nci->debugging);
if ( !peerman_write(nci->chain,peers,setting(nci,"peers"),nci->debugging) )
{
PostMessage( "net: failed to write peer list\n");
exit(1);
}
}
char *addnode = setting(nci,"addnode");
if (addnode)
peerman_addstr(nci->chain->default_port,peers,addnode,nci->debugging);
peerman_sort(peers);
if (nci->debugging)
PostMessage( "net: have %u/%zu peers\n",bp_hashtab_size(peers->map_addr),clist_length(peers->addrlist));
nci->peers = peers;
}
static void init_nci(struct net_child_info *nci)
{
nci->read_fd = -1;
nci->write_fd = -1;
//nci->blocks_fd = -1;
//init_peers(nci);
nci->conns = parr_new(NC_MAX_CONN, NULL);
//nci->eb = event_base_new();
nci->daemon_running = true;
}
void oldsend_getblocks(struct net_child_info *nci)
{
struct msg_getblocks gb;
msg_getblocks_init(&gb);
blkdb_locator(&nci->db, NULL, &gb.locator);
cstring *s = ser_msg_getblocks(&gb);
printf("oldsend_getblocks\n");
nc_conn_send(nci,0, "getblocks", s->str, s->len);
cstr_free(s, true);
msg_getblocks_free(&gb);
}
static bool nc_msg_inv(struct net_child_info *nci,struct nc_conn *conn)
{
struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len };
struct msg_vinv mv, mv_out;
bool rc = false;
msg_vinv_init(&mv);
msg_vinv_init(&mv_out);
if (!deser_msg_vinv(&mv, &buf))
goto out;
if (nci->debugging && mv.invs && mv.invs->len == 1)
{
struct bp_inv *inv = parr_idx(mv.invs, 0);
char hexstr[BU256_STRSZ];
bu256_hex(hexstr, &inv->hash);
char typestr[32];
switch (inv->type)
{
case MSG_TX: strcpy(typestr, "tx"); break;
case MSG_BLOCK: strcpy(typestr, "block"); break;
default: sprintf(typestr, "unknown 0x%x", inv->type); break;
}
PostMessage( "net: %s inv %s %s\n",conn->addr_str, typestr, hexstr);
}
else if (nci->debugging && mv.invs)
PostMessage( "net: %s inv (%zu sz)\n",conn->addr_str, mv.invs->len);
if (!mv.invs || !mv.invs->len)
goto out_ok;
/* scan incoming inv's for interesting material */
unsigned int i;
for (i = 0; i < mv.invs->len; i++)
{
struct bp_inv *inv = parr_idx(mv.invs, i);
switch (inv->type)
{
case MSG_BLOCK:
if (!blkdb_lookup(&nci->db, &inv->hash) && !have_orphan(nci,&inv->hash))
msg_vinv_push(&mv_out, MSG_BLOCK, &inv->hash);
break;
case MSG_TX:
default:
break;
}
}
/* send getdata, if they have anything we want */
if (mv_out.invs && mv_out.invs->len)
{
cstring *s = ser_msg_vinv(&mv_out);
rc = nc_conn_send(nci,conn, "getdata", s->str, s->len);
cstr_free(s, true);
}
out_ok:
rc = true;
out:
msg_vinv_free(&mv);
msg_vinv_free(&mv_out);
return rc;
}
ssize_t fwritev(FILE *fp,const struct iovec *iov,int iovcnt)
{
int i; int32_t bytes_written = 0;
fprintf(stderr,"fwritev.%d from %ld: ",iovcnt,(long)ftell(fp));
for (i = 0; i < iovcnt; i++)
{
int len = (int32_t)fwrite(iov[i].iov_base,1,iov[i].iov_len,fp);
if ( len != iov[i].iov_len )
{
printf("len.%d != %d iov[i].iov_len\n",len,(int32_t)iov[i].iov_len);
//DWORD err = GetLastError();
//errno = ewin_to_posix_error(err);
bytes_written = -1;
break;
}
bytes_written += len;
}
fprintf(stderr,"%d bytes\n",bytes_written);
return bytes_written;
}
static bool nc_msg_verack(struct net_child_info *nci,struct nc_conn *conn)
{
if (conn->seen_verack)
return false;
conn->seen_verack = true;
if (nci->debugging)
PostMessage( "net: %s verack\n",conn->addr_str);
/*
* When a connection attempt is made, the peer is deleted
* from the peer list. When we successfully connect,
* the peer is re-added. Thus, peers are immediately
* forgotten if they fail, on the first try.
*/
conn->peer.last_ok = time(NULL);
conn->peer.n_ok++;
conn->peer.addr.nTime = (uint32_t) conn->peer.last_ok;
peerman_add(conn->nci->peers, &conn->peer, true);
/* request peer addresses */
if ((conn->protover >= CADDR_TIME_VERSION) && (!nc_conn_send(nci,conn, "getaddr", NULL, 0)))
return false;
/* request blocks */
bool rc = true;
time_t now = time(NULL);
time_t cutoff = now - (24 * 60 * 60);
if (conn->nci->last_getblocks < cutoff)
{
struct msg_getblocks gb;
msg_getblocks_init(&gb);
blkdb_locator(&nci->db, NULL, &gb.locator);
cstring *s = ser_msg_getblocks(&gb);
rc = nc_conn_send(nci,conn, "getblocks", s->str, s->len);
cstr_free(s, true);
msg_getblocks_free(&gb);
conn->nci->last_getblocks = now;
}
return rc;
}
static bool nc_conn_send(struct net_child_info *nci,struct nc_conn *conn, const char *command,const void *data, size_t data_len)
{
int32_t i;
cstring *msg = message_str(nci->chain->netmagic, command, data, (uint32_t)data_len);
for (i=0; i<msg->len; i++)
printf("%02x ",msg->str[i] & 0xff);
printf("nc_conn_send cmd.(%s) len.%d\n",command,(int32_t)msg->len);
return(0);
}
static bool nc_msg_addr(struct net_child_info *nci,struct nc_conn *conn)
{
struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len };
struct msg_addr ma;
bool rc = false;
msg_addr_init(&ma);
if (!deser_msg_addr(conn->protover, &ma, &buf))
goto out;
unsigned int i;
time_t cutoff = time(NULL) - (7 * 24 * 60 * 60);
if (nci->debugging)
{
unsigned int old = 0;
for (i = 0; i < ma.addrs->len; i++)
{
struct bp_address *addr = parr_idx(ma.addrs, i);
if (addr->nTime < cutoff)
old++;
}
PostMessage( "net: %s addr(%zu addresses, %u old)\n",conn->addr_str, ma.addrs->len, old);
}
/* ignore ancient addresses */
if (conn->protover < CADDR_TIME_VERSION)
goto out_ok;
/* feed addresses to peer manager */
for (i = 0; i < ma.addrs->len; i++) {
struct bp_address *addr = parr_idx(ma.addrs, i);
if (addr->nTime > cutoff)
peerman_add_addr(conn->nci->peers, addr, false);
}
out_ok:
rc = true;
out:
msg_addr_free(&ma);
return rc;
}
/*libevent stubs
#define EV_READ 1
#define EV_WRITE 2
#define EV_PERSIST 4
struct event *event_new(struct event_base *evbase,int32_t fd,int32_t flags,void *funcp,void *conn) { return(0); }
void event_base_loopbreak(struct event_base *evbase) {}
void event_base_dispatch(struct event_base *evbase) {}
void event_base_free(struct event_base *evbase) {}
struct event_base *event_base_new() { return(0); }
void event_del(struct event *ev) {}
void event_free(struct event *ev) {}
int32_t event_add(struct event *ev,struct timeval *tval) { return(-1); }
// end stubs */
enum { NC_MAX_CONN = 8, };
//static unsigned int net_conn_timeout = 11;
/*
static void nc_conn_kill(struct net_child_info *nci,struct nc_conn *conn);
static bool nc_conn_read_enable(struct net_child_info *nci,struct nc_conn *conn);
static bool nc_conn_read_disable(struct net_child_info *nci,struct nc_conn *conn);
static bool nc_conn_write_enable(struct net_child_info *nci,struct nc_conn *conn);
static bool nc_conn_write_disable(struct net_child_info *nci,struct nc_conn *conn);*/
static bool nc_conn_message(struct net_child_info *nci,struct nc_conn *conn)
{
char *command = conn->msg.hdr.command;
/* verify correct network */
printf("got message.(%s)\n",command);
if (memcmp(conn->msg.hdr.netmagic, nci->chain->netmagic, 4))
{
PostMessage( "net: %s invalid network\n",conn->addr_str);
return false;
}
/* incoming message: version */
//if ( !strncmp(command,"version",12) )
// return nc_msg_version(nci,conn);
/* "version" must be first message */
if (!conn->seen_version)
{
PostMessage( "net: %s 'version' not first\n",conn->addr_str);
return false;
}
/* incoming message: verack */
if (!strncmp(command,"verack",12))
return nc_msg_verack(nci,conn);
/* "verack" must be second message */
if (!conn->seen_verack)
{
PostMessage( "net: %s 'verack' not second\n",conn->addr_str);
return false;
}
/* incoming message: addr */
if (!strncmp(command, "addr", 12))
return nc_msg_addr(nci,conn);
/* incoming message: inv */
else if (!strncmp(command, "inv", 12))
return nc_msg_inv(nci,conn);
/* incoming message: block */
else if (!strncmp(command, "block", 12))
return nc_msg_block(nci,conn);
if (nci->debugging)
PostMessage( "net: %s unknown message %s\n",conn->addr_str,command);
/* ignore unknown messages */
return true;
}
static void init_log(struct net_child_info *nci)
{
char *log_fn = setting(nci,"log");
if (!log_fn || !strcmp(log_fn, "-"))
nci->plog = stdout;
else {
nci->plog = fopen(log_fn, "a");
if (!nci->plog) {
perror(log_fn);
exit(1);
}
}
setvbuf(nci->plog, NULL, _IONBF, BUFSIZ);
}
static void init_blkdb(struct net_child_info *nci)
{
if (!blkdb_init(&nci->db, nci->chain->netmagic, &nci->chain_genesis))
{
PostMessage( "blkdb init failed\n");
exit(1);
}
char *blkdb_fn = 0;//setting(nci,"blkdb");
if (!blkdb_fn)
return;
if ((access(blkdb_fn, F_OK) == 0) && !blkdb_read(nci->chain->hastimestamp,&nci->db, blkdb_fn))
{
PostMessage( "blkdb read failed\n");
exit(1);
}
if ( (nci->db.fp= fopen(blkdb_fn,"rb+")) == 0 )
nci->db.fp= fopen(blkdb_fn,"wb+");
if ( nci->db.fp == 0 )
{
PostMessage( "blkdb file open failed: %s\n", strerror(errno));
exit(1);
}
//nci->db.fd = open(blkdb_fn,O_WRONLY | O_APPEND | O_CREAT | O_LARGEFILE, 0666);
//if (nci->db.fd < 0) {
// PostMessage( "blkdb file open failed: %s\n", strerror(errno));
// exit(1);
//}
}
static void init_blocks(struct net_child_info *nci)
{
char blocks_fn[512];
sprintf(blocks_fn,"%s.blocks",nci->coin);
if ( (nci->blocks_fp= fopen(blocks_fn,"rb+")) == 0 )// O_RDWR | O_CREAT | O_LARGEFILE, 0666);
nci->blocks_fp = fopen(blocks_fn,"wb+");
if ( nci->blocks_fp == 0 )
{
PostMessage( "blocks file open failed: %s\n", strerror(errno));
exit(1);
}
fseek(nci->blocks_fp,0,SEEK_END);
off64_t flen = ftell(nci->blocks_fp);
printf("opened.(%s) flen.%llu\n",blocks_fn,(long long)flen);
if ( flen == (off64_t)-1 )
{
PostMessage( "blocks file lseek64 failed: %s\n", strerror(errno));
exit(1);
}
if ( flen == 0 )
init_block0(nci);
}
static void shutdown_daemon(struct net_child_info *nci)
{
if ( nci->blocks_fp != 0 )
fclose(nci->blocks_fp);
bool rc = peerman_write(nci->chain,nci->peers,setting(nci,"peers"),nci->debugging);
PostMessage( "net: %s %u/%zu peers\n",rc ? "wrote" : "failed to write",bp_hashtab_size(nci->peers->map_addr),clist_length(nci->peers->addrlist));
if ( nci->plog != stdout && nci->plog != stderr )
{
fclose(nci->plog);
nci->plog = NULL;
}
if ( setting(nci,"free") )
{
shutdown_nci(nci);
bp_hashtab_unref(nci->orphans);
bp_hashtab_unref(nci->settings);
blkdb_free(&nci->db);
bp_utxo_set_free(&nci->uset);
}
}
static bool nc_msg_block(struct net_child_info *nci,struct nc_conn *conn)
{
struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len };
struct iovec iov[2]; char hexstr[BU256_STRSZ]; struct bp_block block; bool rc = false;
bp_block_init(&block);
if ( !deser_bp_block(nci->chain->hastimestamp,&block,&buf) )
goto out;
bp_block_calc_sha256(&block);
bu256_hex(hexstr,&block.sha256);
if ( nci->debugging )
PostMessage("net: %s block %s\n",conn->addr_str,hexstr);
if ( !bp_block_valid(&block) )
{
PostMessage("net: %s invalid block %s\n",conn->addr_str,hexstr);
goto out;
}
if ( blkdb_lookup(&nci->db,&block.sha256) || have_orphan(nci,&block.sha256) )
goto out_ok;
iov[0].iov_base = &conn->msg.hdr;
iov[0].iov_len = sizeof(conn->msg.hdr);
iov[1].iov_base = (void *)buf.p;
iov[1].iov_len = conn->msg.hdr.data_len;
printf("hdr.%d len.%d\n",(int32_t)sizeof(conn->msg.hdr),(int32_t)buf.len);
size_t total_write = iov[0].iov_len + iov[1].iov_len;
//off64_t fpos64 = lseek64(nci->blocks_fd, 0, SEEK_CUR);
//fseek(nci->blocks_fp, 0, SEEK_CUR);
off64_t fpos64 = ftell(nci->blocks_fp);
if ( fpos64 == (off64_t)-1 )
{
PostMessage( "blocks: lseek64 failed %s\n",
strerror(errno));
goto out;
}
//errno = 0;
ssize_t bwritten = fwritev(nci->blocks_fp,iov,ARRAY_SIZE(iov));
if ( bwritten != total_write )
{
PostMessage( "blocks: write failed %s\n",strerror(errno));
goto out;
}
if ( !process_block(nci,&block,fpos64) )
{
PostMessage( "blocks: process-block failed\n");
goto out;
}
out_ok:
rc = true;
out:
bp_block_free(&block);
return rc;
}
static bool spend_tx(bool script_verf,struct bp_utxo_set *uset, const struct bp_tx *tx,unsigned int tx_idx, unsigned int height)
{
bool is_coinbase = (tx_idx == 0);
struct bp_utxo *coin;
int64_t total_in = 0, total_out = 0;
unsigned int i;
/* verify and spend this transaction's inputs */
if (!is_coinbase)
{
for (i = 0; i < tx->vin->len; i++)
{
struct bp_txin *txin;
struct bp_txout *txout;
txin = parr_idx(tx->vin, i);
coin = bp_utxo_lookup(uset, &txin->prevout.hash);
if (!coin || !coin->vout)
return false;
if (coin->is_coinbase && ((coin->height + COINBASE_MATURITY) > height))
return false;
txout = NULL;
if (txin->prevout.n >= coin->vout->len)
return false;
txout = parr_idx(coin->vout, txin->prevout.n);
total_in += txout->nValue;
if (script_verf && !bp_verify_sig(coin, tx, i, /* SCRIPT_VERIFY_P2SH */ 0, 0))
return false;
if (!bp_utxo_spend(uset, &txin->prevout))
return false;
}
}
for (i = 0; i < tx->vout->len; i++)
{
struct bp_txout *txout;
txout = parr_idx(tx->vout, i);
total_out += txout->nValue;
}
if (!is_coinbase)
{
if (total_out > total_in)
return false;
}
/* copy-and-convert a tx into a UTXO */
coin = calloc(1, sizeof(*coin));
bp_utxo_init(coin);
if (!bp_utxo_from_tx(coin, tx, is_coinbase, height))
return false;
/* add unspent outputs to set */
bp_utxo_set_add(uset, coin);
return true;
}
static bool spend_block(struct net_child_info *nci,const struct bp_block *block,unsigned int height)
{
struct bp_tx *tx;
unsigned int i;
for (i = 0; i < block->vtx->len; i++)
{
tx = parr_idx(block->vtx, i);
if (!spend_tx(nci->script_verf,&nci->uset, tx, i, height))
{
char hexstr[BU256_STRSZ];
bu256_hex(hexstr, &tx->sha256);
PostMessage( "brd: spent_block tx fail %s\n", hexstr);
return false;
}
}
return true;
}
static bool process_block(struct net_child_info *nci,const struct bp_block *block,int64_t fpos)
{
struct blkdb_reorg reorg; struct blkinfo *bi = bi_new();
fprintf(stderr,"process_block sha256 %llx\n",*(long long *)&block->sha256);
bu256_copy(&bi->hash, &block->sha256);
bp_block_copy_hdr(&bi->hdr, block);
bi->n_file = 0;
bi->n_pos = fpos;
if ( blkdb_add(&nci->db,bi,&reorg) == 0 )
{
PostMessage( "brd: blkdb add fail fpos.%ld\n",(long)fpos);
goto err_out;
}
/* FIXME: support reorg */
assert(reorg.conn == 1);
assert(reorg.disconn == 0);
if ( bu256_equal(&nci->db.best_chain->hash,&bi->hdr.sha256) ) // if best chain, mark TX's as spent
{
if ( spend_block(nci,block,bi->height) == 0 )
{
char hexstr[BU256_STRSZ];
bu256_hex(hexstr, &bi->hdr.sha256);
PostMessage("brd: block spend fail %u %s\n",bi->height, hexstr);
// FIXME: bad record is now in blkdb
goto err_out;
}
}
return true;
err_out:
bi_free(bi);
return false;
}
static bool read_block_msg(struct net_child_info *nci,struct p2p_message *msg, int64_t fpos)
{
struct const_buffer buf = { msg->data, msg->hdr.data_len };
struct bp_block block; bool rc = false;
// unknown records are invalid
printf("read_block_msg\n");
if ( strncmp(msg->hdr.command,"block",sizeof(msg->hdr.command)) )
{
printf("invalid cmd.(%s) != block\n",msg->hdr.command);
return false;
}
bp_block_init(&block);
if ( deser_bp_block(nci->chain->hastimestamp,&block,&buf) == 0 )
{
PostMessage( "brd: block deser fail\n");
goto out;
}
bp_block_calc_sha256(&block);
if (!bp_block_valid(&block))
{
PostMessage( "brd: block not valid\n");
goto out;
}
printf("call process_block\n");
rc = process_block(nci,&block,fpos);
out:
bp_block_free(&block);
return rc;
}
static void read_blocks(struct net_child_info *nci)
{
//int fd = nci->blocks_fd;
int32_t n = 0; FILE *fp = nci->blocks_fp;
struct p2p_message msg = {};
bool read_ok = true;
int64_t fpos = 0;
printf("read_blocks from pos %ld\n",(long)ftell(fp));
while ( fread_message(fp,&msg,&read_ok) )
{
printf("iter.%d netmagic.%x\n",n++,*(int32_t *)nci->chain->netmagic);
if ( memcmp(msg.hdr.netmagic,nci->chain->netmagic,4) )
{
PostMessage("blocks file: invalid network magic\n");
exit(1);
}
//strcpy(msg.hdr.command,"block");
if ( !read_block_msg(nci,&msg,fpos) )
exit(1);
fpos += P2P_HDR_SZ;
fpos += msg.hdr.data_len;
fpos = ftell(fp);
}
printf("read_blocks finished loop\n");
if ( !read_ok )
{
PostMessage("blocks file: read failed\n");
exit(1);
}
free(msg.data);
}
static void readprep_blocks_file(struct net_child_info *nci)
{
// if no blk index, but blocks are present, read and index all block data (several gigabytes)
if ( nci->blocks_fp != 0 )
{
rewind(nci->blocks_fp);
if ( nci->db.fp == 0 )
read_blocks(nci);
else
{
printf("seek to end\n");
// TODO: verify that blocks file offsets are present in blkdb
//if ( lseek(nci->blocks_fd, 0, SEEK_END) == (off_t)-1 )
if ( fseek(nci->blocks_fp,0,SEEK_END) == (off_t)-1 )
{
PostMessage( "blocks file: seek failed: %s\n",strerror(errno));
exit(1);
}
}
}
}
static void init_orphans(struct net_child_info *nci)
{
nci->orphans = bp_hashtab_new_ext(bu256_hash, bu256_equal_,(bp_freefunc) bu256_free, (bp_freefunc) buffer_free);
}
static bool have_orphan(struct net_child_info *nci,const bu256_t *v)
{
return bp_hashtab_get(nci->orphans, v);
}
bool add_orphan(struct net_child_info *nci,const bu256_t *hash_in, struct const_buffer *buf_in)
{
if (have_orphan(nci,hash_in))
return false;
bu256_t *hash = bu256_new(hash_in);
if (!hash) {
PostMessage( "OOM\n");
return false;
}
struct buffer *buf = buffer_copy(buf_in->p, buf_in->len);
if (!buf) {
bu256_free(hash);
PostMessage( "OOM\n");
return false;
}
bp_hashtab_put(nci->orphans, hash, buf);
return true;
}
struct nc_conn
{
bool dead;
int fd;
struct peer peer;
char addr_str[64];
bool ipv4;
bool connected;
struct event *ev;
struct net_child_info *nci;
struct event *write_ev;
clist *write_q; /* of struct buffer */
unsigned int write_partial;
struct p2p_message msg;
void *msg_p;
unsigned int expected;
bool reading_hdr;
unsigned char hdrbuf[P2P_HDR_SZ];
bool seen_version;
bool seen_verack;
uint32_t protover;
};
static bool process_block(struct net_child_info *nci,const struct bp_block *block, int64_t fpos);
static bool have_orphan(struct net_child_info *nci,const bu256_t *v);
static bool add_orphan(struct net_child_info *nci,const bu256_t *hash_in, struct const_buffer *buf_in);
/*struct bp_hashtab *settings;
//const struct chain_info *chain = NULL;
bu256_t chain_genesis;
uint64_t instance_nonce;
bool debugging = false;
FILE *plog = NULL;
static const char *const_settings[] =
{
"net.connect.timeout=11",
"addnode=127.0.0.1",
"peers=brd.peers",
"dns=1",
//"blkdb=brd.blkdb",
"blocks=brd.blocks",
//"log=brd.log",
};*/
static void init_block0(struct net_child_info *nci)
{
if ( nci->blocks_fp != 0 )
{
cstring *msg0 = message_str(nci->chain->netmagic,"block",nci->chain->genesis_hashdata,(int32_t)sizeof(nci->chain->genesis_hashdata));
ssize_t bwritten = fwrite(msg0->str,1,msg0->len,nci->blocks_fp);
if ( bwritten != msg0->len )
{
PostMessage( "blocks write0 failed: %s\n", strerror(errno));
exit(1);
}
cstr_free(msg0,true);
off64_t fpos64 = ftell(nci->blocks_fp);
if ( fpos64 == (off64_t)-1 )
{
PostMessage( "blocks lseek0 failed: %s\n", strerror(errno));
exit(1);
}
PostMessage("blocks: genesis block written\n");
}
}
static void shutdown_nci(struct net_child_info *nci)
{
peerman_free(nci->peers);
//nc_conns_gc(nci, true);
assert(nci->conns->len == 0);
//parr_free(nci->conns, true);
//event_base_free(nci->eb);
}int32_t iguana_send(struct iguana_info *coin,void *_conn,uint8_t *serialized,char *cmd,int32_t len)
{
return(nc_conn_send(coin,_conn,cmd,&serialized[sizeof(struct iguana_msghdr)],len));
int32_t numsent; struct nc_conn *conn = _conn;
len = iguana_sethdr((void *)serialized,coin->chain->netmagic,cmd,&serialized[sizeof(struct iguana_msghdr)],len);
if ( (numsent= (int32_t)send(conn->addr.usock,serialized,len,0)) < 0 )
{
printf("%s: numsent.%d vs len.%d errno.%d usock.%d\n",cmd,numsent,len,errno,conn->addr.usock);
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
printf("bad errno.%d\n",errno);
return(-errno);
}
if ( 0 )
{
/*struct buffer *buf = calloc(1, sizeof(struct buffer));
buf->p = malloc(len), memcpy(buf->p,serialized,len);
buf->len = len;
conn->write_q = clist_append(conn->write_q,buf);
nc_conn_read_disable(coin,conn);
nc_conn_write_enable(coin,conn);*/
}
}
else if ( numsent < len )
{
if ( 0 )
{
/*conn->write_q = clist_append(conn->write_q, buf);
conn->write_partial = (uint32_t)numsent;
buf->p = malloc(len), memcpy(buf->p,serialized,len);
buf->len = len;
conn->write_q = clist_append(conn->write_q,buf);
nc_conn_read_disable(coin,conn);
nc_conn_write_enable(coin,conn);*/
}
//int32_t i;
//for (i=0; i<numsent; i++)
// printf("%02x ",serialized[i]);
printf("Sent.%d of %d for %s\n",numsent,len,cmd);
}
printf("iguana send.%d\n",numsent);
return(numsent);
}
/*struct net_child_info
{
struct peer_manager *peers;
void *conns;
struct event_base *eb;
struct bp_hashtab *settings;
struct wallet *cur_wallet;
const struct chain_info *chain;
bits256 chain_genesis;
uint64_t instance_nonce;
int32_t debugging;
FILE *plog;
struct iguana_blocks blocks;
struct bp_hashtab *orphans;
//struct bp_utxo_set uset;
//int blocks_fd;
FILE *blocks_fp;
//bool script_verf;
//bool daemon_running;
// int32_t lbsock;
char coin[16];
time_t last_getblocks;
};*/
///struct iguana_peer addrs[10];
while ( bestheight > 0 && bestheight > oldbestheight )
{
prevhash = iguana_prevblockhash(blocks,new_best);
if ( (prev= iguana_findblock(&space,blocks,prevhash)) != 0 && prev->height > 0 )
{
new_best = prevhash;
bestheight = prev->height;
reorg_info->conn++;
printf("connect.%d: newbest.%s oldheight.%d newheight.%d\n",reorg_info->conn,bits256_str(new_best),oldbestheight,bestheight);
} else break;
}
// unlikely case: old best chain has greater height
while ( oldbestheight > 0 && bestheight > 0 && oldbestheight > bestheight )
{
old_best = iguana_prevblockhash(blocks,old_best);
if ( (prev= iguana_findblock(&space,blocks,prevhash)) != 0 && prev->height > 0 )
{
oldbestheight = prev->height;
reorg_info->disconn++;
printf("unlikely case: disconn.%d %s\n",reorg_info->disconn,bits256_str(old_best));
} else break;
}
// height matches, but we are still walking parallel chains
while ( oldbestheight > 0 && bestheight > 0 && memcmp(old_best.bytes,new_best.bytes,sizeof(old_best)) != 0 )
{
new_best = iguana_prevblockhash(blocks,new_best);
bestheight = iguana_height(blocks,new_best);
reorg_info->conn++;
old_best = iguana_prevblockhash(blocks,old_best);
oldbestheight = iguana_height(blocks,old_best);
reorg_info->disconn++;
printf("parallel case\n");
}
/*bits256 iguana_PoW(struct iguana_info *coin,int32_t height)
{
int32_t h; bits256 sum; struct iguana_block *ptr,space;
if ( height > 0 )
{
h = (height / 1000);
sum = coin->blocks.PoW[h];
h *= 1000;
while ( ++h <= height )
{
if ( (ptr= iguana_block(&space,coin,h)) != 0 )
sum = bits256_add(sum,bits256_from_compact(ptr->bits));
else
{
printf("error getting block[%u]\n",h);
break;
}
}
}
else
{
iguana_block(&space,coin,0);
sum = bits256_from_compact(space.bits);
}
return(sum);
}*/
/*BIGNUM cur_work,test; bits256 x,sum; char ystr[512],xstr[512];
BN_init(&cur_work);
BN_init(&test);
u256_from_compact(&cur_work,0x1d00ffff);
PoW_str(ystr,sizeof(ystr),&cur_work);
printf("y.(%s) ",ystr);
BN_add(&test,&cur_work,&cur_work);
PoW_str(ystr,sizeof(ystr),&test);
printf("sum.(%s) ",ystr);
PoW_conv(&test,0x1d00ffff);
PoW_str(xstr,sizeof(xstr),&test);
x = bits256_from_compact(0x1d00ffff);
sum = bits256_add(x,x);
printf("xstr.(%s) x.(%s) sum.(%s)\n",xstr,bits256_str(x),bits256_lstr(sum));
getchar();*/
void u256_from_compact(BIGNUM *vo,uint32_t c);
int32_t PoW_conv(BIGNUM *PoW,uint32_t nBits)
{
BN_init(PoW);
u256_from_compact(PoW,nBits);
return(0);
}
int32_t PoW_add(BIGNUM *sum,BIGNUM *a,BIGNUM *b)
{
if ( BN_add(sum,a,b) == 0 )
return(-1);
return(0);
}
void PoW_free(BIGNUM *a) { BN_clear_free(a); }
int32_t PoW_cmp(BIGNUM *test,BIGNUM *hwm) { return(BN_cmp(test,hwm)); }
void PoW_str(char *str,int32_t maxlen,BIGNUM *v);
/*static void nc_conns_gc(struct parr *conns,bool free_all)
{
struct nc_conn *conn; clist *dead = NULL; uint32_t i,n_gc = 0;
// build list of dead connections
for (i=0; i<conns->len; i++)
{
conn = parr_idx(conns,i);
if ( free_all || conn->dead )
dead = clist_prepend(dead,conn);
}
// remove and free dead connections
clist *tmp = dead;
while ( tmp )
{
struct nc_conn *conn = tmp->data;
tmp = tmp->next;
parr_remove(conns,conn);
nc_conn_free(conn);
n_gc++;
}
clist_free(dead);
fprintf(stderr,"net: gc'd %u connections\n",n_gc);
}*/
/*static struct nc_conn *nc_conn_new(const struct peer *peer)
{
struct nc_conn *conn;
conn = calloc(1, sizeof(*conn));
if (!conn)
return NULL;
conn->fd = -1;
peer_copy(&conn->peer, peer);
bn_address_str(conn->addr_str, sizeof(conn->addr_str), conn->peer.addr.ip);
return conn;
}*/
/*static bool nc_conn_start(struct iguana_info *coin,struct nc_conn *conn)
{
char errpfx[64];
printf("start connection.(%s)\n",conn->addr_str);
conn->ipv4 = 1;//is_ipv4_mapped(conn->peer.addr.ip);
conn->fd = socket(conn->ipv4 ? AF_INET : AF_INET6,SOCK_STREAM,IPPROTO_TCP);
if ( conn->fd < 0 )
{
sprintf(errpfx, "socket %s", conn->addr_str);
perror(errpfx);
return false;
}
int flags = fcntl(conn->fd,F_GETFL,0);
if ( (flags < 0) || (fcntl(conn->fd,F_SETFL,flags | O_NONBLOCK) < 0) )
{
sprintf(errpfx, "socket fcntl %s", conn->addr_str);
perror(errpfx);
return false;
}
struct sockaddr *saddr;
struct sockaddr_in6 saddr6;
struct sockaddr_in saddr4;
socklen_t saddr_len;
if (conn->ipv4)
{
memset(&saddr4, 0, sizeof(saddr4));
saddr4.sin_family = AF_INET;
memcpy(&saddr4.sin_addr.s_addr,&conn->peer.addr.ip[12],4);
saddr4.sin_port = htons(conn->peer.addr.port);
saddr = (struct sockaddr *) &saddr4;
saddr_len = sizeof(saddr4);
}
else
{
memset(&saddr6, 0, sizeof(saddr6));
saddr6.sin6_family = AF_INET6;
memcpy(&saddr6.sin6_addr.s6_addr,&conn->peer.addr.ip[0], 16);
saddr6.sin6_port = htons(conn->peer.addr.port);
saddr = (struct sockaddr *) &saddr6;
saddr_len = sizeof(saddr6);
}
// initiate TCP connection
if ( connect(conn->fd,saddr,saddr_len) < 0 )
{
if ( errno != EINPROGRESS )
{
sprintf(errpfx, "socket connect %s", conn->addr_str);
perror(errpfx);
return false;
}
}
return true;
}*/
int32_t rc,lbsock=-1,timeout=1000,priority=1; uint8_t magic[4] = { 0xf9, 0xbe, 0xb4, 0xd9 };
if ( 0 )
{
int32_t testsock,testsock2; char buf[512];
testsock2 = nn_socket(AF_SP,NN_CRYPTO);
testsock = nn_socket(AF_SP,NN_CRYPTO);
rc = nn_setsockopt(testsock,NN_SOL_SOCKET,NN_CRYPTO_MAGIC,magic,4);
rc = nn_setsockopt(testsock2,NN_SOL_SOCKET,NN_CRYPTO_MAGIC,magic,4);
nn_bind(testsock2,"crypto://127.0.0.1:9999");
nn_connect(testsock,"crypto://127.0.0.1:9999");
nn_send(testsock,"hello",6,0);
nn_recv(testsock2,buf,sizeof(buf),0);
printf("bind side got.(%s)\n",buf);
nn_send(testsock2,"gotmsg",7,0);
nn_recv(testsock,buf,sizeof(buf),0);
printf("connect side got.(%s)\n",buf);
getchar();
}
//if ( (lbsock= nn_socket(AF_SP,NN_CRYPTO)) >= 0 )
{
rc = nn_setsockopt(lbsock,NN_SOL_SOCKET,NN_CRYPTO_MAGIC,magic,4);
printf("rc.%d from NN_CRYPTO_MAGIC\n",rc);
rc = nn_setsockopt(lbsock,NN_SOL_SOCKET,NN_SNDPRIO,&priority,sizeof(priority));
rc = nn_setsockopt(lbsock,NN_SOL_SOCKET,NN_RCVTIMEO,&timeout,sizeof(timeout));
rc = nn_setsockopt(lbsock,NN_SOL_SOCKET,NN_SNDTIMEO,&timeout,sizeof(timeout));
printf("rc.%d from NN_SNDPRIO\n",rc);
//if ( nn_connect(lbsock,"crypto://127.0.0.1:8883") >= 0 )
//if ( nn_connect(lbsock,"tcp://127.0.0.1:50447") >= 0 )
{
iguana_main("bitcoin","BTC",1); //NODE_NETWORK);
getchar();
}
}
/*struct iguana_kvitem *iguana_kvitemptr(struct iguanakv *kv,void *value)
{
struct iguana_kvitem *item = 0;
if ( kv != 0 && value != 0 )
{
value = (void *)((long)value - (kv)->keysize);
item = (void *)((long)value - ((long)item->keyvalue - (long)item));
}
return(item);
}*/
void iguana_savepeers(struct iguana_info *coin)
{
uint32_t peerind,itemind; struct iguana_peer *addr,space; char ipaddr[64];
for (peerind=1; peerind<=coin->latest.maxpeers; peerind++)
{
if ( iguana_RWmmap(0,&space,coin,coin->peers,peerind) == 0 )
{
strcpy(ipaddr,space.ipaddr);
//printf("peerind.%d -> (%s)\n",peerind,ipaddr);
if ( (addr= iguana_kvread(coin,&space,&itemind,coin->peers,space.A.ip)) != 0 )
{
if ( peerind == itemind )
{
if ( iguana_RWmmap(1,addr,coin,coin->peers,peerind) != 0 )
printf("error RWmap.1 peerind.%d -> (%s)\n",peerind,ipaddr);
} else printf("mismatched peerind.%d vs itemind.%d for (%s)\n",peerind,itemind,ipaddr);
}
} else printf("error reading peerind.%d\n",peerind);
}
iguana_syncmap(&coin->peers->state.M,0);
}
if ( strcmp("peers",kv->name) == 0 )
{
struct iguana_peer *addr = (void *)sp->space;
addr->seen_verack = 0;
checkip[0] = 0;
addr->peerind = itemind;
if ( addr->ipaddr[0] != 0 )
{
ipbits = (uint32_t)calc_ipbits(addr->ipaddr);
expand_ipbits(checkip,ipbits);
}
if ( addr->ipaddr[0] == 0 || strcmp(checkip,addr->ipaddr) != 0 )
{
printf("bad record.(%s) vs (%s) %d vs %d\n",checkip,addr->ipaddr,addr->peerind,itemind);
i = keysize;
}
else printf("add n.%d skipped.%d (%s) vs (%s).%x i.%d\n",n,skipped,addr->ipaddr,checkip,ipbits,i);
}
void *iguana_kvsavepeer(struct iguana_info *coin,struct iguanakv *kv,struct iguana_kvitem *item,uint64_t args,void *key,void *value,int32_t valuesize)
{
FILE *fp = (FILE *)args; struct iguana_peer *addr; uint32_t data[4],ipbits,flag = 0;
if ( args != 0 && (addr= value) != 0 )
{
printf("%p %s iterarg.%d verack.%d killed.%d\n",addr,addr->ipaddr,kv->iterarg,addr->seen_verack,addr->dead);
if ( kv->iterarg == 0 && addr->seen_verack != 0 )
flag = 1;
else if ( kv->iterarg == 1 && addr->dead != 0 )
flag = 1;
else if ( kv->iterarg == 2 && (addr->seen_verack == 0 && addr->dead == 0) )
flag = 1;
if ( flag != 0 )
{
ipbits = (uint32_t)calc_ipbits(addr->ipaddr);
data[0] = ipbits;
data[1] = addr->lastcontact;
data[2] = addr->nStartingHeight;
data[3] = addr->pingtime;
if ( fwrite(data,1,sizeof(data),fp) != sizeof(data) )
{
printf("Error saving key.[%x]\n",ipbits);
return(key);
}
}
}
return(0);
}
long iguana_savepeers(struct iguana_info *coin)
{
FILE *fp; long retval = -1; int32_t iter; char fname[512],*str = "good";
for (iter=0; iter<3; iter++)
{
coin->peers->iterarg = iter;
sprintf(fname,"%s.%s",coin->peers->name,str);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( iguana_kviterate(coin,coin->peers,(uint64_t)fp,iguana_kvsavepeer) == 0 )
{
printf("save %ld to HDD\n",ftell(fp));
retval = ftell(fp);
}
else printf("error saving item at %ld\n",ftell(fp));
fclose(fp);
} else printf("error creating(%s)\n",fname);
if ( iter == 0 )
str = "errpeer";
else str = "newpeer";
}
coin->updatedpeers = 0;
return(retval);
}
/*void iguana_open_connection(struct iguana_info *coin,char *ipaddr)
{
int32_t i,n; struct iguana_peer addrs[10];
memset(addrs,0,sizeof(addrs));
n = iguana_connect(addrs,(int32_t)(sizeof(addrs)/sizeof(*addrs)),ipaddr,coin->chain->default_port);
if ( n > 0 )
{
for (i=0; i<n; i++) // almost always n is just 1
iguana_addpeer(coin,&addrs[i]);
return;
}
}*/
void iguana_updatepeer(struct iguana_info *coin,struct iguana_peer *addr)
{
printf("UPDATE PEER.(%s) total.%d relayers.%d\n",addr->ipaddr,coin->numpeers,coin->numrelayers);
iguana_kvwrite(coin,coin->peers,addr->A.ip,addr,sizeof(*addr),(uint32_t *)&addr->peerind);
coin->updatedpeers++;
}
void *iguana_kvpurgepeer(struct iguana_info *coin,struct iguanakv *kv,struct iguana_kvitem *item,uint64_t args,void *key,void *value,int32_t valuesize)
{
struct iguana_peer *addr; int32_t lag;
if ( args != 0 && (addr= value) != 0 && addr->sendtime != 0 )
{
if ( (lag= (kv->iteruarg - addr->sendtime)) == 0 )
lag = 1;
if ( kv->iterarg == 0 || lag > kv->iterarg )
{
kv->iterarg = lag;
strcpy((char *)args,addr->ipaddr);
}
}
return(0);
}
void *iguana_loop(void *_coin)
{
struct iguana_info *coin = _coin;
while ( 1 )
{
/*if ( 1 && (ipaddr= queue_dequeue(&coin->newpeersQ,1)) != 0 )
{
iguana_open_connection(coin,ipaddr);
printf("check newpeer.(%s)\n",ipaddr);
free_queueitem(ipaddr);
}*/
sleep(1);
}
return(0);
}
void shutdown_daemon(struct iguana_info *coin)
{
if ( coin->blocks.db != 0 )
{
//iguana_kvsave(coin->blocks.db);
iguana_kvfree(coin,coin->blocks.db);
}
}
/*if ( coin->numpeers > 16 )
{
coin->peers->iteruarg = (uint32_t)time(NULL);
coin->peers->iterarg = 0;
if ( iguana_kviterate(coin,coin->peers,(uint64_t)ipaddr,iguana_kvpurgepeer) == 0 )
printf("lag.%d (%s) peer purged\n",coin->peers->iterarg,ipaddr);
else printf("error: lag.%d (%s) peer purged\n",coin->peers->iterarg,ipaddr);
}
*/
//for (iter=0; iter<2; iter++)
{
fpos = n = m = fixed = skipped = 0;
if ( (fp= fopen(sp->fname,"rb")) != 0 )
{
fseek(fp,fpos,SEEK_SET);
while ( fread(sp->space,2,valuesize,fp) == valuesize )
{
//printf("m.%d\n",m);
itemind = m++;
for (i=0; i<keysize; i++)
if ( ((uint8_t *)sp->space)[kv->keyoffset + i] != 0 )
break;
if ( i != keysize )
{
if ( itemind != n )
{
fseek(fp,fpos,SEEK_SET);
memset((void *)((long)sp->space + valuesize),0,valuesize);
fwrite((void *)((long)sp->space + valuesize),1,valuesize,fp);
fseek(fp,(long)n * valuesize,SEEK_SET);
fwrite(sp->space,1,valuesize,fp);
fixed++;
//printf("itemind.%d vs n.%d skipped.%d\n",itemind,n,skipped);
itemind = n;
}
if ( iter == 1 )
{
iguana_kvwrite(coin,kv,(void *)((long)sp->space + kv->keyoffset),sp->space,valuesize,&itemind);
}
n++;
} skipped++;
fseek(fp,(long)m * valuesize,SEEK_SET);
}
printf("iter.%d fixed.%d %s added %d items, skipped.%d keysize.%d keyoffset.%d valuesize.%d\n",iter,fixed,kv->name,n,skipped,kv->keysize,kv->keyoffset,kv->valuesize);
fclose(fp);
//getchar();
}
}
void iguana_killpeer(struct iguana_info *coin,struct iguana_peer *addr)
{
if ( addr->seen_verack != 0 )
{
addr->dead = 1;
addr->seen_verack = 0;
coin->numrelayers -= addr->relayflag;
coin->numpeers--;
printf("KILL PEER.(%s) peerind.%u total.%d relayers.%d\n",addr->ipaddr,addr->peerind,coin->numpeers,coin->numrelayers);
iguana_kvwrite(coin,coin->peers,addr->A.ip,addr,sizeof(*addr),(uint32_t *)&addr->peerind);
coin->updatedpeers++;
}
}
/*for (j=0; j<addr->numreferrals; j++)
if ( ipbits == addr->referrals[j] )
break;
if ( j == addr->numreferrals )
{
if ( addr->numreferrals < sizeof(addr->referrals)/sizeof(*addr->referrals) )
addr->referrals[addr->numreferrals++] = ipbits;
iguana_possible_peer(coin,ipaddr);
}*/
int32_t iguana_blockchain(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_msgblock *blk,uint8_t *serialized,bits256 hash2,int32_t checkpointi)
{
struct iguana_blocks *blocks; double PoW; struct iguana_block *prev,*check,space; int32_t i,height,firsttxidind;
blocks = &coin->blocks;
/*if ( (check= iguana_findblock(coin,&space,hash2)) != 0 )
{
if ( checkpointi >= 0 && check->height == coin->checktip_heights[checkpointi]+1 )
{
coin->checkpointips[checkpointi] = hash2;
coin->checktip_heights[checkpointi]++;
coin->rawblocks++;
printf("iguana_blockchain: duplicate block height.%d checkpointi.%d tipheight.%d rawblocks.%d\n",check->height,checkpointi,coin->checktip_heights[checkpointi],coin->rawblocks);
}
return(check->height);
}
for (i=0; i<coin->chain->numcheckpoints; i++)
{
if ( memcmp(coin->chain->checkpoints_data[i].bytes,hash2.bytes,sizeof(hash2)) == 0 )
{
height = coin->chain->checkblocks[i];
coin->checktip_heights[i] = height;
printf("checkpointi.%d height.%d rawblocks.%d\n",i,height,coin->rawblocks);
iguana_addblock(coin,hash2,blk,height,-1,0.); // add to block map, orphans and all
return(0);
}
if ( memcmp(coin->chain->checkpoints_data[i].bytes,blk->H.prev_block.bytes,sizeof(blk->H.prev_block)) == 0 )
{
height = coin->chain->checkblocks[i] + 1;
coin->checktip_heights[i] = height;
coin->checkpointips[i] = hash2;
coin->rawblocks++;
printf("checkpointi.%d height.%d <- (%s) rawblocks.%d\n",i,height,bits256_str(hash2),coin->rawblocks);
iguana_addblock(coin,hash2,blk,height,-1,0.); // add to block map, orphans and all
return(0);
}
if ( memcmp(coin->checkpointips[i].bytes,blk->H.prev_block.bytes,sizeof(blk->H.prev_block)) == 0 )
{
height = ++coin->checktip_heights[i];
coin->checkpointips[i] = hash2;
coin->rawblocks++;
printf("checkpointi.%d height.%d rawblocks.%d\n",i,height,coin->rawblocks);
iguana_addblock(coin,hash2,blk,height,-1,0.); // add to block map, orphans and all
return(0);
}
}*/
if ( (prev= iguana_findblock(coin,&space,blk->H.prev_block)) == 0 )
{
fprintf(stderr,"iguana_blockchain no prev block.(%s)\n",bits256_str(blk->H.prev_block));
return(-1);
}
else
{
height = prev->height + 1;
PoW = (PoW_from_compact(blk->H.bits) + prev->PoW);
firsttxidind = (prev->firsttxidind + prev->txn_count);
if ( PoW <= coin->blocks.best_chain_work )
height = 0;
}
//printf("NEWHT.%d (%s) PoW %.15f prev.%d prevPoW %.15f\n",height,bits256_str(hash2),blk->PoW,prev->height,prev->PoW);
iguana_addblock(coin,addr,hash2,blk,height,firsttxidind,PoW); // add to block map, orphans and all
if ( height == 0 )
{
printf("%s chain not best\n",bits256_str(hash2));
return(-1);
}
if ( memcmp(blocks->best_chain.bytes,blk->H.prev_block.bytes,sizeof(blocks->best_chain)) != 0 )
{
printf("prev.(%s) doesnt connect to previous bestchain\n",bits256_str(blk->H.prev_block));
printf("mark as orphans from old bestchain.(%s) till it connects to mainchain\n",bits256_str(blocks->best_chain));
getchar();
}
return(height);
}
int32_t iguana_possible_peer(struct iguana_info *coin,char *ipaddr)
{
struct iguana_peer *space,*addr,addrs[8]; uint32_t i,n,peerind = (uint32_t)-1;
if ( strncmp("0.0.0",ipaddr,5) != 0 && strcmp("0.0.255.255",ipaddr) != 0 && strcmp("1.0.0.0",ipaddr) != 0 )
{
memset(addrs,0,sizeof(addrs));
n = iguana_connect(addrs,(int32_t)(sizeof(addrs)/sizeof(*addrs)),ipaddr,coin->chain->default_port,0);
if ( n > 0 )
{
for (i=0; i<1; i++) // n is almost always 1
{
strcpy(addrs[i].coinstr,coin->name);
space = calloc(1,sizeof(*space));
peerind = -1;
//portable_mutex_lock(&coin->netmutex);
if ( (addr= iguana_kvread(coin,space,(uint32_t *)&peerind,coin->peers,ipaddr)) == 0 )
memcpy(space,&addrs[i],sizeof(*space));
else if ( addr->usock >= 0 || addr->pending != 0 )
break;
peerind = -1;
if ( iguana_kvwrite(coin,coin->peers,ipaddr,space,sizeof(*space),(uint32_t *)&peerind) != 0 )
{
//portable_mutex_unlock(&coin->netmutex);
//printf("%p %s ADD PEER.(%s) peerind.%u max.%u total.%d relayers.%d numkeys.%d\n",&addrs[i],space->coinstr,space->ipaddr,peerind,coin->latest.maxpeers,coin->numpeers,coin->numrelayers,coin->peers->numkeys);
space->coin = coin;
if ( coin->numthreads < 3 || (coin->numthreads < IGUANA_MAXPEERS/2 && iguana_metric(space) > coin->avemetric) || (coin->numthreads >= IGUANA_MAXPEERS/2 && coin->numthreads < IGUANA_MAXPEERS) )
{
peerind = -1;
//portable_mutex_lock(&coin->netmutex);
if ( (addr= iguana_kvread(coin,space,(uint32_t *)&peerind,coin->peers,ipaddr)) != 0 )
{
coin->numthreads++;
//portable_mutex_unlock(&coin->netmutex);
addr->coin = coin;
if ( coin->chain->numcheckpoints > 0 )
addr->checkpointi = (coin->nextcheckpointi++ % coin->chain->numcheckpoints);
else addr->checkpointi = -1;
portable_thread_create(iguana_startconnection,addr);
} //else portable_mutex_unlock(&coin->netmutex);
}
//printf("possible.(%s)\n",ipaddr);
}
else
{
//portable_mutex_unlock(&coin->netmutex);
printf("error writing?\n");
}
}
}
}
return(0);
}
/*iguana_send_version(coin,addr,coin->myservices);
if ( addr->dead == 0 && addr->usock >= 0 )
{
printf("connected and version sent to usock.%d (%s) numpings.%d\n",addr->usock,addr->ipaddr,addr->numpings);
if ( coin->chain->numcheckpoints > 0 )
addr->checkpointi = (coin->nextcheckpointi++ % coin->chain->numcheckpoints);
printf("%s uses checkpointi.%d\n",addr->ipaddr,addr->checkpointi);
//nexti = (coin->chain->numcheckpoints/IGUANA_MAXPEERS) * addr->checkpointi;
iguana_advancechain(coin,addr,addr->checkpointi);//nexti++ % coin->chain->numcheckpoints);
}*/
/*iguana_send_version(coin,addr,coin->myservices);
if ( addr->dead == 0 && addr->usock >= 0 )
{
printf("connected and version sent to usock.%d (%s) numpings.%d\n",addr->usock,addr->ipaddr,addr->numpings);
if ( coin->chain->numcheckpoints > 0 )
addr->checkpointi = (coin->nextcheckpointi++ % coin->chain->numcheckpoints);
printf("%s uses checkpointi.%d\n",addr->ipaddr,addr->checkpointi);
//nexti = (coin->chain->numcheckpoints/IGUANA_MAXPEERS) * addr->checkpointi;
iguana_advancechain(coin,addr,addr->checkpointi);//nexti++ % coin->chain->numcheckpoints);
}*/
void iguana_pollconnection(struct iguana_info *coin,struct iguana_peer *addr)
{
/*if ( addr->last_getblocks < time(NULL) - (24 * 60 * 60) )
{
memset(stophash.bytes,0,sizeof(stophash));
n = iguana_locator(coin,hashes,(int32_t)(sizeof(hashes)/sizeof(*hashes)));
iguana_send_hashes(coin,addr->protover < GETHEADERS_VERSION ? "getblocks" : "getheaders",addr,stophash,hashes,n);
printf("send %s to %s\n",addr->protover < GETHEADERS_VERSION ? "getblocks" : "getheaders",addr->ipaddr);
addr->last_getblocks = time(NULL);
}*/
}
void iguana_checkpoint(struct iguana_info *coin,struct iguana_peer *addr,bits256 hash2,int32_t height)
{
struct iguana_block block;
memset(&block,0,sizeof(block));
block.prev_block = hash2;
block.height = (height + 1);
//printf("write (%s) to %d\n",bits256_str(hash2),height+1);
iguana_RWmmap(1,&block,coin,coin->blocks.db,height+1);
//iguana_syncmap(coin->blocks.db,0);
}
int32_t iguana_addblockhash(struct iguana_info *coin,struct iguana_peer *addr,int32_t *heightp,bits256 hash2,bits256 nexthash)
{
struct iguana_block *block,*next,space,nextspace;
*heightp = -1;
if ( (block= iguana_findblock(coin,&space,hash2)) != 0 )
{
*heightp = block->height;
if ( (next= iguana_findblock(coin,&nextspace,nexthash)) == 0 )
{
iguana_checkpoint(coin,addr,nexthash,block->height + 1);
//iguana_audit(coin);
return(0);
}
else if ( next->height != block->height + 1 )
{
printf("iguana_addblockhash: mismatched next height.%d vs height.%d+1\n",next->height,block->height);
//iguana_audit(coin);
return(-1);
}
else
{
//iguana_audit(coin);
return(iguana_blockdata(coin,block));
}
}
//iguana_audit(coin);
return(0);
}
int32_t iguana_advancecmp(bits256 hashes[2],int32_t n,int32_t cmpa,int32_t cmpb)
{
//printf("n.%d cmpa.%d cmpb.%d\n",n,cmpa,cmpb);
if ( bits256_nonz(hashes[0]) != 0 && bits256_nonz(hashes[1]) == 0 && (cmpa == 0 || n < cmpa) && (cmpb == 0 || n < cmpb) )
return(1);
//printf("failed cmp %d %d %d %d\n",bits256_nonz(hashes[0]) != 0,bits256_nonz(hashes[1]) == 0,(cmpa == 0 || n < cmpa),(cmpb == 0 || n < cmpb));
return(0);
}
/*void iguana_advancechain(struct iguana_info *coin,struct iguana_peer *addr,int32_t checkpointi)
{
bits256 stophash,hashes[10]; int32_t islocal,n = 0; char *cmd = "";
memset(stophash.bytes,0,sizeof(stophash));
islocal = (strcmp("127.0.0.1",addr->ipaddr) == 0);
//printf("blockhash %d, blockhdr.%d block.%d height.%d\n",addr->maxblockhash_height,addr->maxblockhdr_height,addr->maxblock_height,addr->height);
if ( (islocal != 0 || addr->protover < GETHEADERS_VERSION) && iguana_advancecmp(addr->maxblockhash,addr->maxblockhash_height,addr->maxblockhdr_height+500,addr->height+2000) != 0 )
{
printf("request blockhashes islocal.%d\n",islocal);
cmd = "getblocks";
addr->maxblockhash[1] = hashes[n++] = coin->blocks.hwmchain;//addr->maxblockhash[0];
}
else if ( islocal != 0 && addr->protover >= GETHEADERS_VERSION && iguana_advancecmp(addr->maxblockhdr,addr->maxblockhdr_height,addr->maxblock_height+500,0) != 0 )
{
cmd = "getheaders";
printf("request headers islocal.%d\n",islocal);
addr->maxblockhdr[1] = hashes[n++] = addr->maxblockhdr[0];
}
else if ( memcmp(coin->blocks.hwmchain.bytes,addr->maxblock[1].bytes,sizeof(bits256)) != 0 ) //if ( iguana_advancecmp(addr->maxblock,addr->maxblock_height,addr->height,0) != 0 )
{
printf("request data\n");
addr->maxblock[0] = addr->maxblock[1] = coin->blocks.hwmchain;
iguana_request_data(coin,addr,coin->blocks.hwmchain,MSG_BLOCK);
return;
}
else
{
//printf("nothing to advance %s\n",addr->ipaddr);
return;
}
n = iguana_locator(coin,hashes,(int32_t)(sizeof(hashes)/sizeof(*hashes))-1,checkpointi);
iguana_send_hashes(coin,cmd,addr,stophash,hashes,n);
}*/
// got functions
void iguana_gotblockhash(struct iguana_info *coin,struct iguana_peer *addr,bits256 hash2,bits256 nexthash,int32_t i,int32_t n)
{
int32_t height; struct iguana_block space; bits256 hashes[2001];
/*if ( iguana_addblockhash(coin,addr,&height,hash2,nexthash) == 0 )
{
//if ( height > (coin->blocks.hwmheight-10) )
// iguana_request_data(coin,addr,nexthash,MSG_BLOCK);
}
if ( height > addr->maxblockhash_height )
{
addr->maxblockhash_height = height;
addr->maxblockhash[0] = hash2;
memset(addr->maxblockhash[1].bytes,0,sizeof(hash2));
}*/
//if ( i > 0 )
//hashes[i-1] = hash2;
iguana_request_data(coin,addr,&hash2,1,MSG_BLOCK);
if ( i == n-1 )
{
hashes[i] = nexthash;
iguana_request_data(coin,addr,&nexthash,1,MSG_BLOCK);
//iguana_request_data(coin,addr,hashes,n,MSG_BLOCK);
bits256 stophash;
memset(stophash.bytes,0,sizeof(stophash));
iguana_send_hashes(coin,"getblocks",addr,stophash,&nexthash,1);
}
height = iguana_height(coin,hash2);
//printf("set gotblockhash.%s %d ht.%d -> %s from %s\n",bits256_str(hash2),height,iguana_height(coin,hash2),bits256_str2(nexthash),addr->ipaddr);
//iguana_audit(coin);
}
int32_t iguana_gotblockhdr(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_msgblock *msg,uint8_t *serialized,int32_t len,bits256 hash2,int32_t checkpointi)
{
int32_t n = 0,height = -1; struct iguana_block space,*block;
//printf("got gotblockhdr.%s from %s, checkpointi.%d\n",bits256_str(hash2),addr->ipaddr,checkpointi);
if ( (block= iguana_findblock(coin,&space,hash2)) != 0 && block->height < coin->blocks.hwmheight )
return(block->height - coin->blocks.hwmheight);
iguana_convblock(&space,msg,-1,0,0.);
if ( (height= iguana_addblock(coin,addr,hash2,&space)) > 0 )
{
n = iguana_lookahead(coin,addr,&hash2,height + 1);
//printf("lookahead.%d\n",n);
}
/*if ( height+1+n > addr->maxblockhdr_height )
{
printf("set new maxblockhdr.%d\n",height+1+n);
addr->maxblockhdr_height = height+1+n;
addr->maxblockhdr[0] = hash2;
memset(addr->maxblockhdr[1].bytes,0,sizeof(hash2));
}*/
//iguana_audit(coin);
return(height);
}
int32_t iguana_queue_ramchain(struct iguana_info *coin,struct iguana_peer *addr,bits256 hash2,int32_t txind,int32_t numtx,struct iguana_msgtx *tx,bits256 txid)
{
int32_t height;
addr->getdatamillis = 0;
if ( addr != 0 && txind == 0 && (height= iguana_height(coin,hash2)) >= 0 )//&& height >= addr->maxblock_height )
{
//printf("got ramchain tx.%s from %s height.%d txind.%d\n",bits256_str(txid),addr!=0?addr->ipaddr:"local",height,txind);
/*printf("set new maxblock.%d\n",height);
addr->maxblock_height = height;
addr->maxblock[0] = hash2;
memset(addr->maxblock[1].bytes,0,sizeof(hash2));*/
}
return(0);
}
void iguana_gottxid(struct iguana_info *coin,struct iguana_peer *addr,bits256 hash2)
{
}
int32_t iguana_addblock(struct iguana_info *coin,struct iguana_peer *addr,bits256 hash2,struct iguana_block *newblock)
{
int32_t h;
//,firsttxidind,txn_count,hwm=0,equivalent = 0;
//double PoW; struct iguana_block *block,space,prevspace;
//height = newblock->height, firsttxidind = newblock->firsttxidind, PoW = newblock->PoW;
//printf("iguana_addblock nBits.%x\n",newblock->bits);
/*if ( (block= iguana_findblock(coin,&space,hash2)) != 0 )
{
if ( height >= 0 )
{
if ( height != block->height )
printf("iguana_addblockhdr: height.%d mismatch vs %d\n",height,block->height);
} else height = block->height;
if ( firsttxidind > 0 )
{
if ( firsttxidind != block->firsttxidind )
printf("iguana_addblockhdr: firsttxidind.%d mismatch vs %d\n",firsttxidind,block->firsttxidind);
} else firsttxidind = block->firsttxidind;
if ( PoW > SMALLVAL )
{
if ( fabs(PoW - block->PoW) > SMALLVAL )
printf("iguana_addblockhdr: PoW.%.15f mismatch vs %.15f\n",PoW,block->PoW);
} else PoW = block->PoW;
if ( (flag= iguana_blockdata(coin,block)) == 0 )
{
printf("write out block.(%s) to %d\n",bits256_str(hash2),height);
iguana_kvwrite(coin,coin->blocks.db,hash2.bytes,newblock,sizeof(*newblock),(uint32_t *)&height);
}
else if ( flag > 0 )
{
space2 = *block;
space2.height = newblock->height;
if ( memcmp(block,&space2,sizeof(*block)) != 0 )
printf("newblock is different from oldblock (%d %d %f) vs (%d %d %f)\n",newblock->height,newblock->firsttxidind,newblock->PoW,block->height,block->firsttxidind,block->PoW);
else
{
equivalent = 1;
}
}
//printf("newblock (%d %d %f) vs old (%d %d %f)\n",newblock->height,newblock->firsttxidind,newblock->PoW,block->height,block->firsttxidind,block->PoW);
//iguana_audit(coin);
}
if ( memcmp(coin->chain->genesis_hashdata,hash2.bytes,sizeof(hash2)) == 0 )
{
PoW = height = txn_count = 0;
prev = 0;
firsttxidind = 1;
hwm = 1;
block = newblock;
printf("adding genesis\n");
}
else if ( (prev= iguana_findblock(coin,&prevspace,newblock->prev_block)) == 0 )
{
printf("hash2.(%s) ",bits256_str(hash2));
fprintf(stderr,"iguana_blockchain no prev block.(%s)\n",bits256_str(newblock->prev_block));
getchar();
return(-1);
}
else
{
if ( height >= 0 && height != prev->height + 1 )
printf("iguana_addblock: height.%d != prev.%d+1\n",height,prev->height);
height = prev->height + 1;
PoW = prev->PoW;
firsttxidind = prev->firsttxidind;
txn_count = prev->txn_count;
}*/
if ( (newblock->height= iguana_setchainvars(coin,addr,&newblock->firsttxidind,&newblock->PoW,hash2,newblock->prev_block,newblock->bits,newblock->txn_count)) != (uint32_t)-1 )
{
if ( newblock->PoW > coin->blocks.hwmPoW )
{
if ( newblock->height+1 > coin->blocks.maxblocks )
coin->blocks.maxblocks = (newblock->height + 1);
h = newblock->height;
iguana_kvwrite(coin,coin->blocks.db,hash2.bytes,newblock,(uint32_t *)&h);
if ( addr != 0 && newblock->height > addr->height )
addr->height = newblock->height;
coin->blocks.hwmheight = newblock->height;
coin->blocks.hwmPoW = newblock->PoW;
coin->blocks.hwmchain = hash2;
coin->latest.blockhash = hash2;
coin->latest.merkleroot = newblock->merkle_root;
coin->latest.timestamp = newblock->timestamp;
coin->latest.numblocks = coin->blocks.hwmheight+1;
coin->latest.numtxidind = newblock->firsttxidind + newblock->txn_count;
//iguana_syncmap(coin->blocks.db,0);
//printf("%s height.%d PoW %f\n",bits256_str(hash2),block->height,block->PoW);
if ( coin->initblocks != 0 )
printf("ADD %d:%d:%d <- (%s) n.%u max.%u PoW %f\n",h,iguana_height(coin,coin->blocks.hwmchain),newblock->height,bits256_str(coin->blocks.hwmchain),coin->blocks.hwmheight+1,coin->blocks.maxblocks,newblock->PoW);
}
}
if ( memcmp(hash2.bytes,coin->blocks.hwmchain.bytes,sizeof(hash2)) != 0 )
{
printf("ORPHAN.%s height.%d PoW %f vs best %f\n",bits256_str(hash2),newblock->height,newblock->PoW,coin->blocks.hwmPoW);
newblock->height = -1;
}
//iguana_audit(coin);
return(newblock->height);
}
/*int32_t iguana_locator(struct iguana_info *coin,bits256 *hashes,int32_t max)
{
int32_t i,n = 0; bits256 prevhash;
hashes[n++] = coin->blocks.hwmchain;
for (i=0; i<max&&n<10; i++)
{
prevhash = iguana_prevblockhash(coin,hashes[n-1]);
if ( bits256_nonz(prevhash) != 0 )
hashes[n++] = prevhash;
else break;
}
printf("iguana_locator n.%d\n",n);
return(n);
}*/
/*bits256 iguana_blockkey(struct iguana_info *coin,struct iguana_block *block)
{
struct iguana_block blocks[2]; int32_t i,n; bits256 hash2;
memset(hash2.bytes,0,sizeof(hash2));
n = (int32_t)(1 + (coin->blocks.db->keyoffset + coin->blocks.db->keysize) / sizeof(struct iguana_block));
if ( n > sizeof(blocks)/sizeof(*blocks) || coin->blocks.db->keysize != sizeof(bits256) )
return(hash2);
for (i=0; i<n; i++)
if ( iguana_block(coin,&blocks[i],block->height+i) == 0 )
return(hash2);
memcpy(hash2.bytes,(void *)((long)&blocks[0] + coin->blocks.db->keyoffset),coin->blocks.db->keysize);
return(hash2);
}*/
int32_t iguana_blockdata(struct iguana_info *coin,struct iguana_block *block)
{
bits256 key = iguana_blockkey(coin,block);
if ( block->height+1 >= (coin->blocks.db->state.M.allocsize / sizeof(*block)) || bits256_nonz(key) == 0 )
return(-1);
else if ( block->height > 0 && (bits256_nonz(block->prev_block) == 0 || fabs(block->PoW) < SMALLVAL) )
{
printf("iguana_blockdata height.%d \n",block->height);
return(0);
}
if ( block->firsttxidind > 0 )
return(1);
return(-1);
}
/*space = mycalloc(1,sizeof(*space));
if ( (addr= iguana_kvread(coin,space,(uint32_t *)&peerind,coin->peers,ipaddr)) == 0 )
{
memcpy(space,&addrs[i],sizeof(*space));
addr = space;
iguana_clear_addrstate(coin,addr);
}
else if ( addr->usock >= 0 || addr->pending != 0 || addr->dead != 0 )
{
printf("%s usock.%d pending.%u dead.%d\n",addr->ipaddr,addr->usock,addr->pending,addr->dead);
break;
}
addr->lastcontact = (uint32_t)time(NULL);
if ( coin->numthreads < IGUANA_MAXTHREADS )//&& (coin->numactive < 3 || (coin->numactive < IGUANA_MAXPEERS/2 && iguana_metric(space) > coin->avemetric) || (coin->numactive >= IGUANA_MAXPEERS/2 && coin->numactive < IGUANA_MAXPEERS)) )
{
addr->pending = (uint32_t)time(NULL);
addr->coin = coin;
peerind = -1;
iguana_kvwrite(coin,coin->peers,ipaddr,addr,(uint32_t *)&peerind);
portable_thread_create(iguana_startconnection,addr);
} else*/
{
int32_t valuesize; void *checkptr;
valuesize = iguana_valuesize(coin,kv);
memset(kv->state.space,0,kv->RAMvaluesize);
checkptr = kv->state.space;
if ( (kv->flags & IGUANA_MAPPED_ITEM) != 0 )
{
value = (void *)((long)value + sizeof(UT_hash_handle));
checkptr = (void *)((long)checkptr + sizeof(UT_hash_handle));
}
if ( iguana_RWmmap(0,kv->state.space,coin,kv,*itemindp) != 0 || memcmp(value,checkptr,valuesize) != 0 )
{
printf("iguana_RWmmap data mismatch after kvwrite\n");
getchar();
}
}
/*init_hexbytes_noT(hexstr,pk_script+1,pk_script[0]);
//printf("(%s).%02x ",hexstr,pk_script[pk_script[0]]);
if ( 1 && pk_script[1] == 4 )
{
pk[0] = 2 + (pk_script[pk_script[0]] & 1);
memcpy(pk+1,pk_script+2,32);
init_hexbytes_noT(hexstr,pk,33);
printf("data.(%s).%d ",hexstr,pk_script[0]);
vcalc_sha256(0,sha256,pk,33);
calc_rmd160(0,rmd160,sha256,sizeof(sha256));
init_hexbytes_noT(hexstr,rmd160,20);
printf("rmd.(%s) ",hexstr);
//decode_hex(rmd160,20,"e34498597d0d4d4be05db1bb7501da985e15aaa5");
btc_convrmd160(coinaddr,coin->chain->addr_pubkey,rmd160);
printf("(%s)\n",coinaddr);
}*/
/*int32_t iguana_possible_peer(struct iguana_info *coin,char *ipaddr)
{
struct iguana_peer *addr=0,addrs[8]; uint32_t i,n;
#ifdef IGUANA_DISABLEPEERS
if ( strcmp(ipaddr,"127.0.0.1") != 0 )
return(0);
#endif
if ( strncmp("0.0.0",ipaddr,5) != 0 && strcmp("0.0.255.255",ipaddr) != 0 && strcmp("1.0.0.0",ipaddr) != 0 )
{
//printf("possible peer.(%s)\n",ipaddr);
memset(addrs,0,sizeof(addrs));
n = iguana_connect(addrs,(int32_t)(sizeof(addrs)/sizeof(*addrs)),ipaddr,coin->chain->default_port,0);
if ( n > 0 )
{
for (i=0; i<1; i++) // n is almost always 1
{
strcpy(addrs[i].coinstr,coin->name);
addr = mycalloc('p',1,sizeof(*addr));
*addr = addrs[i];
iguana_clear_peerstate(coin,addr);
queue_enqueue("connectionQ",&coin->peers.connectionQ,&addr->DL);
return(0);
}
}
}
if ( addr != 0 )
myfree(addr,sizeof(*addr));
return(0);
}*/
/*{
for (i=0; i<n; i++)
{
//printf("%p coinstr.(%s)\n",coin,coin->name);
//if ( addr->ipv6 != 0 )
// err = iguana_connectsocket(1,addr,(struct sockaddr *)&addr->saddr6,sizeof(addr->saddr6));
//else err = iguana_connectsocket(1,addr,(struct sockaddr *)&addr->saddr4,sizeof(addr->saddr4));
if ( err < 0 )
{
fprintf(stderr,"close connect %s: %s numpings.%d\n",addr->ipaddr,strerror(-err),addr->numpings);
iguana_iAkill(coin,addr);
}
else
{
iguana_iAconnected(coin,addr);
addr->ready = (uint32_t)time(NULL);
}
}
}*/
void iguana_clear_peerstate(struct iguana_info *coin,struct iguana_peer *addr)
{
addr->usock = -1;
addr->pingnonce = 0;
addr->ready = addr->dead = addr->pending = 0;
addr->startsend = addr->startrecv = 0;
addr->bufsize = 0; addr->buf = 0;
strcpy(addr->symbol,coin->symbol);
strcpy(addr->coinstr,coin->name);
//memset(&addr->DL,0,sizeof(addr->DL));
//memset(&addr->sendQ,0,sizeof(addr->sendQ));
//memset(&addr->msgcounts,0,sizeof(addr->msgcounts));
}
/**/
/*
void iguana_activate(struct iguana_info *coin,struct iguana_peer *addr)
{
int32_t i;//,peerind = -1;
if ( coin->peers.numactive > 0 )
{
for (i=0; i<coin->peers.numactive; i++)
if ( strcmp(coin->peers.active[i].ipaddr,addr->ipaddr) == 0 )
break;
if ( i != coin->peers.numactive )
{
printf("duplicate activation.%s rejected\n",addr->ipaddr);
return;
}
}
coin->peers.active[coin->peers.numactive] = *addr;
myfree(addr,sizeof(*addr));
addr = &coin->peers.active[coin->peers.numactive++];
iguana_send_version(coin,addr,coin->myservices);
printf("ACTIVE.%d peer.(%s) numthreads.%d\n",coin->peers.numactive,addr->ipaddr,coin->numthreads);
//if ( strcmp(addr->ipaddr,"127.0.0.1") == 0 )
// portable_thread_create(iguana_localhost,addr);
}
void iguana_connections(struct iguana_info *coin)
{
int32_t i,j,firsti,peerind; uint32_t ipbits; struct iguana_peer *addr;
if ( coin->numthreads < IGUANA_MAXTHREADS && (addr= queue_dequeue(&coin->peers.connectionQ,0)) != 0 )
{
if ( addr->pending == 0 )
{
for (i=0; i<sizeof(coin->peers.active)/sizeof(*coin->peers.active); i++)
if ( strcmp(coin->peers.active[i].ipaddr,addr->ipaddr) == 0 )
break;
if ( i == coin->peers.numactive )
{
if ( coin->peers.numpending < sizeof(coin->peers.pending)/sizeof(*coin->peers.pending) )
{
ipbits = (uint32_t)calc_ipbits(addr->ipaddr);
firsti = -1;
for (i=0; i<sizeof(coin->peers.pending)/sizeof(*coin->peers.pending); i++)
{
if ( coin->peers.pending[i] == 0 )
firsti = i;
else if ( coin->peers.pending[i] == ipbits )
break;
}
if ( i == sizeof(coin->peers.pending)/sizeof(*coin->peers.pending) )
{
printf("PENDING.%-16s pending.%u ready.%u numpending.%d\n",addr->ipaddr,addr->pending,addr->ready,coin->numiAddrs);
coin->peers.pending[firsti] = ipbits;
addr->pending = (uint32_t)time(NULL);
strcpy(addr->symbol,coin->symbol);
iguana_launch(coin,"connection",iguana_startconnection,addr,0);
}
}
queue_enqueue("retryQ",&coin->peers.retryQ,&addr->DL);
}
}
else
{
if ( addr->ready != 0 )
iguana_activate(coin,addr);
else if ( addr->dead == 0 )
queue_enqueue("retryQ",&coin->peers.retryQ,&addr->DL);
}
}
}*/
//printf("parsed.%d firstvout.%d+%d firstvin.%d+%d: %s got.%d %s v %d\n",coin->blocks.parsedblocks,block->firstvout,block->numvouts,block->firstvin,block->numvins,addr->ipaddr,block->height,bits256_str(block->hash2),coin->blocks.hwmheight);
/*if ( block->height == coin->blocks.parsedblocks )
iguana_parseblock(coin,block,tx,numtx);
else
{
printf("height.%d vs parsed.%d hwm.%d\n",block->height,coin->blocks.parsedblocks,coin->blocks.hwmheight);
iguana_addpending(coin,addr->ipbits,block,tx,numtx);
}*/
int32_t iguana_polliter(struct iguana_info *coin)
{
struct pollfd fds[IGUANA_MAXPEERS];
struct iguana_peer *addr,*addrs[IGUANA_MAXPEERS];
int32_t i,n,nonz,flag,timeout=10;
memset(fds,0,sizeof(*fds));
memset(addrs,0,sizeof(*addrs));
flag = 0;
for (i=n=nonz=0; i<IGUANA_MAXPEERS; i++)
{
addr = &coin->peers.active[i];
fds[i].fd = -1;
if ( addr->usock < 0 || addr->dead != 0 || addr->ready == 0 )
{
if ( addr->pending == 0 )
addrs[n++] = addr;
continue;
}
if ( addr->startrecv == 0 )
{
fds[i].fd = addr->usock;
fds[i].events |= POLLIN;
nonz++;
}
}
if ( nonz != 0 && poll(fds,IGUANA_MAXPEERS,timeout) > 0 )
{
for (i=0; i<IGUANA_MAXPEERS; i++)
{
addr = &coin->peers.active[i];
if ( addr->usock < 0 || addr->dead != 0 || addr->ready == 0 )
continue;
//if ( addr->usock >= 0 && addr->ready > 0 )
// printf("%d/%d %d/%d startrecv.%u usock.%d dead.%d ready.%u\n",fds[i].events,fds[i].fd,POLLIN,POLLOUT,addr->startrecv,addr->usock,addr->dead,addr->ready);
if ( addr->startrecv == 0 && (fds[i].revents & POLLIN) != 0 )
{
void iguana_processmsg(void *ptr);
flag++;
strcpy(addr->symbol,coin->symbol);
if ( 0 )
{
addr->startrecv = (uint32_t)time(NULL);
iguana_launch("processmsg",iguana_processmsg,addr,0);
} else iguana_processmsg(addr);
}
}
}
return(flag);
}
int32_t oldiguana_getdata(struct iguana_info *coin,struct iguana_peer *addr)
{
struct iguana_overlap *ov = &addr->OV;
int32_t height,flag,elapsed,j,n = 0; bits256 hash2; double reqpsec,kbpsec;
//printf("iguana_getdata.(%s) ov.%p %p\n",addr->ipaddr,ov,addr);
//printf("addr height.%d vs parsed.%d\n",addr->height,coin->blocks.parsedblocks);
if ( ov->overlap == 0 )
{
if ( strcmp("127.0.0.1",addr->ipaddr) == 0 )
ov->overlap = IGUANA_MAXOVERLAP/2;
else ov->overlap = IGUANA_MAXOVERLAP/8;
iguana_teststart(coin,addr);
}
if ( addr != 0 && addr->dead == 0 && addr->usock >= 0 && addr->height >= coin->blocks.parsedblocks )
{
for (flag=0; flag<ov->overlap; flag++)
{
if ( addr->waiting[flag] == 0 )
{
for (height=coin->blocks.parsedblocks; height<coin->longestchain&&height<coin->blocks.parsedblocks+IGUANA_MAXPENDING; height++)
{
if ( coin->recvblocks != 0 && coin->recvblocks[height] != 0 )
continue;
if ( strcmp("127.0.0.1",addr->ipaddr) == 0 )
{
if ( height > coin->blocks.parsedblocks+IGUANA_MAXPENDING/2 )
{
if ( n == 0 )
{
hash2 = iguana_blockhash(coin,coin->blocks.parsedblocks);
iguana_request_data(coin,addr,&hash2,1,MSG_BLOCK);
}
return(n);
}
}
else
{
if ( height < coin->blocks.parsedblocks+IGUANA_MAXPENDING/2 )
continue;
}
hash2 = iguana_blockhash(coin,height);
for (j=0; j<IGUANA_MAXOVERLAP; j++)
if ( memcmp(addr->waitinghash[j].bytes,hash2.bytes,sizeof(hash2)) == 0 )
break;
if ( j != sizeof(addr->waitinghash)/sizeof(*addr->waitinghash) )
continue;
if ( height < coin->numwaitingbits && GETBIT(coin->waitingbits,height) == 0 )
{
if ( bits256_nonz(hash2) != 0 )
{
addr->waiting[flag] = (uint32_t)time(NULL);
addr->waitinghash[flag] = hash2;
if ( ov->numreqs++ >= ov->overlap )
{
if ( ov->numreqs == ov->overlap )
ov->numreqs = ov->overlap;
elapsed = (uint32_t)(time(NULL) - ov->teststart) + 1;
reqpsec = (double)ov->numreqs / elapsed;
kbpsec = (double)ov->reqrecv / (1024 * elapsed);
dxblend(&ov->Rsec,reqpsec,0.99);
dxblend(&ov->KBsec,kbpsec,0.99);
if ( kbpsec*reqpsec >= (ov->Rsec * ov->KBsec) )
ov->faster++;
else ov->slower++;
if ( ((ov->faster + ov->slower) % 1000) == 0 )
printf("OV.%-2d i.%-2d +%-4d -%-4d | h.%d %u | %5.1f/sec %5.3f/kB vs %5.1f/sec %5.3f/kB %5.1f %s\n",ov->overlap,flag,ov->faster,ov->slower,height,addr->waiting[flag],ov->Rsec,ov->KBsec,reqpsec,kbpsec,reqpsec*kbpsec-ov->Rsec*ov->KBsec,addr->ipaddr);
if ( time(NULL) > ov->teststart+60 || (ov->faster+ov->slower > ov->overlap*2 && ov->faster > 10*ov->slower) )
iguana_teststart(coin,addr);
elapsed = (uint32_t)(time(NULL) - coin->starttime) + 1;
reqpsec = (double)coin->totalpackets / elapsed;
kbpsec = (double)coin->totalrecv / (1024 * elapsed);
dxblend(&coin->Rsec,reqpsec,0.99);
dxblend(&coin->KBsec,kbpsec,0.99);
}
n++;
//printf("request.%d bit.%d\n",height,GETBIT(coin->waitingbits,height));
iguana_request_data(coin,addr,&hash2,1,MSG_BLOCK);
SETBIT(coin->waitingbits,height);
break;
}
}
}
}
}
}
if ( strcmp(addr->ipaddr,"127.0.0.1") == 0 && n == 0 && coin->recvblocks != 0 && coin->recvblocks[height] == 0 )
{
hash2 = iguana_blockhash(coin,coin->blocks.parsedblocks);
iguana_request_data(coin,addr,&hash2,1,MSG_BLOCK);
}
return(n);
//printf("full.%d numactive.%d hwm.%d\n",coin->fullblocks,coin->numactive,coin->blocks.hwmheight);
}
void iguana_teststart(struct iguana_info *coin,struct iguana_peer *addr)
{
static uint32_t lastdisp;
int32_t dir; struct iguana_overlap *ov = &addr->OV;
dir = (ov->overlap - ov->prevoverlap);
ov->prevoverlap = ov->overlap;
if ( dir != 0 )
{
if ( time(NULL) > lastdisp+60 )
{
lastdisp = (uint32_t)time(NULL);
printf("ov.%-2d M%4.1f-> %5.1f/sec %6.2f/kb M%4.1f |fast.%-3d vs slow.%-3d d.%-2d | ",ov->overlap,ov->prevmetric,ov->Rsec,ov->KBsec,ov->Rsec*ov->KBsec,ov->faster,ov->slower,dir);
printf("all %5.1f/sec, %6.2fKB %s\n",coin->Rsec,coin->KBsec,addr->ipaddr);
}
if ( ov->faster > ov->slower )
{
if ( (dir > 0 && ov->overlap < IGUANA_MAXOVERLAP) || (dir < 0 && ov->overlap > 1) )
ov->overlap += dir;
//else printf("max overlap\n");
//printf("increase by dir.%d -> overlap.%d\n",dir,addr->overlap);
}
else if ( dir > 0 && ov->overlap > 1 )
{
ov->overlap--;
//printf("since slower, reduce overlap to overlap.%d\n",addr->overlap);
}
else if ( dir < 0 && ov->overlap < IGUANA_MAXOVERLAP )
{
ov->overlap++;
//printf("since faster, increase overlap to overlap.%d\n",addr->overlap);
}
//else printf("at lowest overlap, cant change\n");
ov->prevmetric = (ov->Rsec * ov->KBsec);
ov->reqrecv = 0;
ov->numreqs = -ov->overlap;
ov->faster = ov->slower = 0;
}
else ov->overlap = 1;
ov->teststart = (uint32_t)time(NULL);
}
void iguana_localhost(void *ptr)
{
struct iguana_info *coin; struct iguana_peer *addr = ptr;
if ( addr != 0 && (coin= iguana_coin(addr->symbol)) != 0 )
{
while ( addr->dead == 0 )
_iguana_processmsg(coin,addr);
}
}
if ( (num= iguana_available(coin,availables)) > 0 )
{
if ( (addr= availables[0]) != 0 )
{
m = iguana_needed(coin,coin->need[0],IGUANA_MAXPENDING/2,0);
n = iguana_needed(coin,coin->need[1],IGUANA_MAXPENDING/2,IGUANA_MAXPENDING/2);
if ( strcmp(addr->ipaddr,"127.0.0.1") == 0 || num == 1 )
{
//printf("m.%d n.%d num.%d\n",m,n,num);
for (i=0; i<m; i++)
{
height = coin->need[0][i];
//printf("%d ",height);
hash2 = iguana_blockhash(coin,height);
iguana_request_data(coin,addr,&hash2,1,MSG_BLOCK);
SETBIT(coin->waitingbits,height);
}
if ( num > 1 )
{
for (i=0; i<n; i++)
{
height = coin->need[1][i];
//printf("%d ",height);
hash2 = iguana_blockhash(coin,height);
iguana_request_data(coin,availables[(i+1) % (num-1)],&hash2,1,MSG_BLOCK);
SETBIT(coin->waitingbits,height);
}
}
}
else
{
for (i=0; i<m; i++)
{
height = coin->need[0][i];
//printf("%d ",height);
hash2 = iguana_blockhash(coin,height);
iguana_request_data(coin,availables[i % num],&hash2,1,MSG_BLOCK);
SETBIT(coin->waitingbits,height);
}
}
if ( 0 && m+n > 0 )
printf("requests\n");
/*if ( m == 0 )
sleep(3);
if ( m+n == 0 )
sleep(10);*/
return(m+n);
} else printf("null available[0]\n");
}
int32_t iguana_needed(struct iguana_info *coin,int32_t *need,int32_t max,int32_t offset)
{
int32_t nonz,m,height;
if ( coin->recvblocks == 0 )
return(0);
nonz = m = 0;
memset(need,0,sizeof(*need) * max);
if ( (time(NULL) - coin->parsetime) > 3 )
need[m++] = coin->blocks.parsedblocks;
for (height=coin->blocks.parsedblocks+offset; height<coin->longestchain&&height<coin->blocks.parsedblocks+max+offset; height++)
{
if ( coin->recvblocks[height] != 0 )
nonz++;
else if ( GETBIT(coin->waitingbits,height) == 0 )
need[m++] = height;
}
return(m);
}
int32_t iguana_available(struct iguana_info *coin,struct iguana_peer *availables[IGUANA_MAXPEERS])
{
int32_t j,n; struct iguana_peer *addr;
memset(availables,0,sizeof(*availables) * IGUANA_MAXPEERS);
for (j=n=0; j<IGUANA_MAXPEERS; j++)
{
addr = &coin->peers.active[j];
if ( addr->height < coin->blocks.parsedblocks || addr == coin->localaddr )
continue;
if ( addr->usock >= 0 && addr->dead == 0 && addr->ready > 0 && iguana_updatewaiting(coin,addr) > 0 )
availables[n++] = addr;
}
return(n);
}
/*int32_t iguana_loadtx(struct iguana_info *coin,struct iguana_peer *addr,bits256 *blockhashp,int32_t txind,int32_t numtx,struct iguana_msgtx *tx,uint8_t *data,int32_t maxsize)
{
int32_t len; bits256 txid;
memset(tx,0,sizeof(*tx));
len = iguana_rwtx(0,data,tx,maxsize,&txid);
if ( blockhashp != 0 )
{
//printf("parse.(%s)\n",bits256_str(*blockhashp));
//if ( (blocknum= iguana_height(coin,*blockhashp)) >= 0 )
if ( iguana_queue_ramchain(coin,addr,*blockhashp,txind,numtx,tx,txid) > 0 )
return(len);
//else printf("cant find blockhash.(%s)\n",bits256_str(*blockhashp));
}
iguana_purgetx(tx,0);
return(len);
}*/
/*for (i=0; i<sizeof(addr->waiting)/sizeof(*addr->waiting); i++)
{
if ( addr->waiting[i] != 0 && time(NULL) > (addr->waiting[i] + 60) )
{
if ( (height= iguana_height(coin,addr->waitinghash[i])) >= 0 )
{
printf("i.%d of %ld ipbits.%x timeout.%s height.%d\n",i,sizeof(addr->waiting)/sizeof(*addr->waiting),addr->ipbits,addr->ipaddr,height);
CLEARBIT(coin->waitingbits,height);
}
addr->waiting[i] = 0;
addr->waitinghash[i] = bits256_zero;
}
if ( addr->waiting[i] == 0 )
n++;
}*/
void *iguana_kvmetriciterator(struct iguana_info *coin,struct iguanakv *kv,struct iguana_kvitem *item,uint64_t args,void *key,void *value,int32_t valuesize)
{
struct iguana_peer *addr = value; double *sortbuf = (double *)args;
if ( addr->numpings > 0 && addr->pingsum > SMALLVAL && item->hh.itemind < kv->numkeys )
{
//printf("%p (%s).%d ind.%d msgs.%d pings.%d %.0fms [%.3f] last.%u lag.%d S.%llu R.%llu\n",sortbuf,addr->ipaddr,addr->usock,item->itemind,addr->numpackets,addr->numpings,addr->pingtime,addr->pingsum/addr->numpings,addr->lastcontact,kv->iteruarg - addr->lastcontact,(long long)addr->totalsent,(long long)addr->totalrecv);
sortbuf = &sortbuf[item->hh.itemind << 1];
sortbuf[0] = iguana_metric(addr);
sortbuf[1] = item->hh.itemind;
}
return(0);
}
int32_t iguana_sendrequests(struct iguana_info *coin,struct iguana_peer *addrs[],int32_t n,int32_t *blocks,int32_t m)
{
int32_t i,height; bits256 hash2;
if ( n > 0 && m > 0 )
{
for (i=0; i<m; i++)
{
height = blocks[i];
hash2 = iguana_blockhash(coin,height);
iguana_request_data(coin,addrs[i % n],&hash2,1,MSG_BLOCK);
SETBIT(coin->waitingbits,height);
}
return(m);
}
return(0);
}
int32_t iguana_getdata(struct iguana_info *coin)
{
int32_t reqs[IGUANA_READAHEAD],height,i,j,m,readahead,offset,numpeers,limit,n = 0; struct iguana_peer *addr,*addrs[IGUANA_MAXPEERS];
if ( coin->R.waitingbits == 0 || coin->R.recvblocks == 0 )
return(0);
capacity = iguana_capacity(coin,&numpeers,addrs);
if ( numpeers == 0 )
return(0);
if ( capacity < numpeers )
capacity = numpeers;
else if ( capacity > IGUANA_READAHEAD )
capacity = IGUANA_READAHEAD;
readahead = (coin->longestchain - coin->blocks.parsedblocks) / numpeers;
for (j=m=0; j<IGUANA_MAXPEERS; j++)
{
//if ( coin->numwaiting > IGUANA_MAXWAITING ) makes it worse
// break;
if ( coin->peers.numranked == 0 )
addr = &coin->peers.active[j];
else
{
if ( j >= coin->peers.numranked )
break;
if ( (addr= coin->peers.ranked[j]) == 0 )
continue;
}
if ( addr->recvblocks == 0 )
limit = 1;
else
{
if ( addr == coin->peers.localaddr )
limit = IGUANA_BUNDLESIZE;
else limit = addr->rank <= 0 ? 1 : (IGUANA_BUNDLESIZE / sqrt(addr->rank));
if ( limit < 1 )
limit = 1;
}
height = coin->blocks.parsedblocks;
if ( readahead < 1 )
readahead = 1;
if ( readahead > IGUANA_READAHEAD )
readahead = IGUANA_READAHEAD;
if ( addr->rank >= 0 && addr->ready > 0 && addr->usock >= 0 && addr->dead == 0 && addr->height > 0 )
{
m++;
//printf("%s: addrht.%d %s p.%d getbit.%d rank.%d\n",addr->ipaddr,addr->height,addr->ipaddr,height,GETBIT(coin->waitingbits,height),addr->rank);
for (i=n=0; i<100000&&n<limit; i++)
{
offset = (((addr->rank > 0) ? addr->rank-1 : m)) * readahead;
height = (coin->blocks.parsedblocks + offset + i);
if ( height > coin->blocks.hwmheight || height > addr->height )
{
//printf("%s: height.%d > hwm.%d || addr %d\n",addr->ipaddr,height,coin->blocks.hwmheight,addr->height);
break;
}
if ( coin->R.numwaiting > IGUANA_MAXWAITING && height > coin->blocks.parsedblocks+100 )
break;
if ( iguana_waitstart(coin,height,addr) == 0 )
{
//printf("%-15s request block.%-6d parsed.%-6d offset.%-4d rank.%-3d numpeers.%d numwaiting.%d\n",addr->ipaddr,height,coin->blocks.parsedblocks,offset,addr->rank,numpeers,coin->R.numwaiting);
n++;
}
}
}
}
return(n);
}
/*else if ( time(NULL) > coin->parsetime+1 )
{
coin->parsetime = (uint32_t)time(NULL);
printf("backstop.%d %s\n",coin->blocks.parsedblocks,bits256_str(iguana_blockhash(coin,coin->blocks.parsedblocks)));
iguana_waitclear(coin,coin->blocks.parsedblocks);
iguana_waitstart(coin,coin->blocks.parsedblocks,0);
iguana_updatewaiting(coin,coin->blocks.parsedblocks+1,100);
}
//else printf("ptr.%p height.%d\n",ptr,height);*/
/*if ( coin->blocks.parsedblocks > initialheight )
initialheight = coin->blocks.parsedblocks;
if ( coin->longestchain > initialheight )
initialheight = coin->longestchain;
iguana_recvinit(coin,coin->R.numwaitingbits);*/
//height = (coin->blocks.hwmheight / IGUANA_HDRSCOUNT) * IGUANA_HDRSCOUNT;
//iguana_queuehdrs(coin,height,iguana_blockhash(coin,height));
int32_t iguana_rwunspentind(struct iguana_info *coin,int32_t rwflag,struct iguana_unspent *U,uint32_t unspentind)
{
if ( rwflag == 0 )
{
memset(U,0,sizeof(*U));
if ( iguana_kvread(coin,coin->unspents,0,U,&unspentind) != 0 )
return(0);
else printf("error getting unspents[%u] when %d\n",unspentind,coin->latest.numunspents);
}
else if ( iguana_kvwrite(coin,coin->unspents,0,U,&unspentind) != 0 )
return(0);
return(-1);
}
void iguana_requests(void *arg)
{
int32_t flag,i,j,n; double sum; struct iguana_peer *addr; struct iguana_info *coin,**coins = arg;
n = (int32_t)coins[0];
coins++;
printf("iguana_requests N.%d\n",n);
while ( 1 )
{
for (i=0; i<n; i++)
{
if ( (coin= coins[i]) != 0 )
{
//portable_mutex_lock(&coin->blocks.mutex);
//if ( iguana_avail(coin,coin->blocks.parsedblocks,10000) < 10000 )
else printf("skip getting data max packets allocated %s\n",mbstr(sum));
//portable_mutex_unlock(&coin->blocks.mutex);
}
}
if ( flag == 0 )
usleep((uint32_t)coin->sleeptime + 1);
}
}
else
{
if ( coin->peers.numranked > 0 && time(NULL) > coin->backstop )
{
int32_t i; bits256 hash2; struct iguana_peer *addr;
i = (rand() % coin->peers.numranked);
hash2 = iguana_blockhash(coin,coin->blocks.parsedblocks);
addr = coin->peers.ranked[i];
if ( addr != 0 && memcmp(hash2.bytes,addr->backstop.bytes,sizeof(hash2)) != 0 )
{
iguana_waitclear(coin,coin->blocks.parsedblocks);
if ( addr != 0 )
{
iguana_waitstart(coin,coin->blocks.parsedblocks,addr);
printf("%s BACKSTOP.%d\n",addr->ipaddr,coin->blocks.parsedblocks);
coin->backstop = (uint32_t)time(NULL);
}
}
}
/*if ( iguana_waitstart(coin,coin->blocks.parsedblocks,addr) == 0 )
{
printf("backstop request.%d to %s\n",coin->blocks.parsedblocks,addr->ipaddr);
addr->backstop = hash2;
}*/
//printf("%s skip %d vs %d ptr.%p\n",addr->ipaddr,coin->blocks.parsedblocks,coin->numwaitingbits,ptr);
}
bits256 iguana_histo(struct iguana_info *coin)
{
double sum = 0.; int32_t i; bits256 seed;
for (i=0; i<0x100; i++)
sum += coin->R.histo[i];
sum /= i;
memset(seed.bytes,0,sizeof(seed));
if ( sum > 0. )
{
for (i=0; i<0x100; i++)
{
printf("%.2f ",coin->R.histo[i]/sum);
if ( coin->R.histo[i] > sum )
SETBIT(seed.bytes,i);
}
}
printf("histo.(%s)\n",bits256_str(seed));
return(seed);
}
struct iguana_state
{
//char name[16];
uint8_t sha256[256 >> 3]; struct sha256_vstate state;
//struct iguana_mappedptr M; struct iguana_space MEM; //queue_t writeQ; portable_mutex_t ;
void *table;
//FILE *fp; uint8_t *space;
//uint64_t maxitems; //uint32_t itemsize,flags;
};
/*struct iguana_overlap
{
double KBsec,Rsec,prevmetric;
uint64_t reqrecv;
uint32_t teststart;
int32_t numreqs,overlap,faster,slower,prevoverlap;
};*/
int32_t iguana_capacity(struct iguana_info *coin,int32_t *nump,struct iguana_peer *addrs[IGUANA_MAXPEERS])
{
struct iguana_peer *addr; int32_t i,n,capacity = 0;
for (i=n=0; i<IGUANA_MAXPEERS; i++)
{
addr = &coin->peers.active[i];
//if ( addr->usock >= 0 )
// printf("%s ht.%d\n",addr->ipaddr,addr->height);
if ( addr->ready > 0 && addr->dead == 0 && addr->usock >= 0 && addr->height > coin->blocks.parsedblocks )
{
capacity += addr->capacity;
addrs[n++] = addr;
}
}
*nump = n;
return(capacity);
}
int32_t iguana_getdata(struct iguana_info *coin)
{
int32_t reqs[IGUANA_READAHEAD],height,i,j,m,readahead,offset,numpeers,limit,n = 0; struct iguana_peer *addr,*addrs[IGUANA_MAXPEERS];
if ( coin->R.waitingbits == 0 || coin->R.recvblocks == 0 )
return(0);
for (i=numpeers=0; i<IGUANA_MAXPEERS; i++)
if ( coin->peers.active[i].usock < 0 )
numpeers++;
if ( numpeers == 0 )
return(0);
readahead = (coin->longestchain - coin->blocks.parsedblocks) / numpeers;
for (j=m=0; j<IGUANA_MAXPEERS; j++)
{
//if ( coin->numwaiting > IGUANA_MAXWAITING ) makes it worse
// break;
if ( coin->peers.numranked == 0 )
addr = &coin->peers.active[j];
else
{
if ( j >= coin->peers.numranked )
break;
if ( (addr= coin->peers.ranked[j]) == 0 )
continue;
}
if ( addr->recvblocks == 0 )
limit = 1;
else
{
if ( addr == coin->peers.localaddr )
limit = IGUANA_EXPIREWINDOW;
else limit = addr->rank <= 0 ? 1 : (IGUANA_EXPIREWINDOW / sqrt(addr->rank));
if ( limit < 1 )
limit = 1;
}
height = coin->blocks.parsedblocks;
if ( readahead < 1 )
readahead = 1;
if ( readahead > IGUANA_EXPIREWINDOW )
readahead = IGUANA_EXPIREWINDOW;
if ( addr->rank >= 0 && addr->ready > 0 && addr->usock >= 0 && addr->dead == 0 && addr->height > 0 )
{
m++;
//printf("%s: addrht.%d %s p.%d getbit.%d rank.%d\n",addr->ipaddr,addr->height,addr->ipaddr,height,GETBIT(coin->waitingbits,height),addr->rank);
for (i=n=0; i<100000&&n<limit; i++)
{
offset = (((addr->rank > 0) ? addr->rank-1 : m)) * readahead;
height = (coin->blocks.parsedblocks + offset + i);
if ( height > coin->blocks.hwmheight || height > addr->height )
{
//printf("%s: height.%d > hwm.%d || addr %d\n",addr->ipaddr,height,coin->blocks.hwmheight,addr->height);
break;
}
//if ( coin->R.numwaiting > IGUANA_MAXWAITING && height > coin->blocks.parsedblocks+100 )
// break;
if ( iguana_waitstart(coin,height,addr) != 0 )
{
addr->capacity--;
//printf("%-15s request block.%-6d parsed.%-6d offset.%-4d rank.%-3d numpeers.%d numwaiting.%d\n",addr->ipaddr,height,coin->blocks.parsedblocks,offset,addr->rank,numpeers,coin->R.numwaiting);
n++;
}
}
}
}
return(n);
}
int32_t newiguana_getdata(struct iguana_info *coin)
{
int32_t reqs[IGUANA_READAHEAD],height,i,j,count,capacity,numpeers,n = 0; struct iguana_peer *addr,*addrs[IGUANA_MAXPEERS];
if ( coin->R.waitingbits == 0 || coin->R.recvblocks == 0 )
return(0);
capacity = iguana_capacity(coin,&numpeers,addrs);
if ( numpeers == 0 )
return(0);
if ( capacity < numpeers )
capacity = numpeers;
else if ( capacity > IGUANA_READAHEAD )
capacity = IGUANA_READAHEAD;
if ( iguana_avail(coin,coin->blocks.parsedblocks,IGUANA_READAHEAD) == IGUANA_READAHEAD )
n = iguana_updatewaiting(coin,reqs,capacity,coin->blocks.parsedblocks + (coin->longestchain - coin->blocks.parsedblocks)/2);
else n = iguana_updatewaiting(coin,reqs,IGUANA_READAHEAD,coin->blocks.parsedblocks);
count = 0;
height = coin->blocks.parsedblocks;
//printf("capacity.%d reqs.%d numpeers.%d\n",capacity,n,numpeers);
if ( n > 0 )
{
for (i=0; i<n; i++)
{
height = reqs[i];
if ( coin->R.numwaiting > IGUANA_MAXWAITING )//&& height > coin->blocks.parsedblocks+100 )
break;
for (j=0; j<numpeers; j++)
{
if ( (addr= addrs[(i+j) % numpeers]) != 0 && addr->capacity > 0 && addr->height >= height )
{
count += iguana_waitstart(coin,height,addr);
break;
}
}
if ( j == numpeers )
{
//printf("leftover.%d n.%d\n",i,n);
if ( (addr= addrs[(i+j) % numpeers]) != 0 && addr->height >= height )
count += iguana_waitstart(coin,height,addr);
break;
}
}
}
//for (i=0; i<numpeers; i++)
// iguana_waitstart(coin,height+IGUANA_READAHEAD*(i+1),addrs[i]);
return(count);
}
/*{
if ( (flag= iguana_processhdrs(coin,blocks,n)) >= 0 )
{
if ( flag == 0 )
{
}
printf("gotheaders flag.%d n.%d (%s) %d vs %d \n",flag,n,bits256_str(blocks[n-1].hash2),iguana_height(coin,blocks[n-1].hash2),coin->blocks.hwmheight);
if ( n > 0 && iguana_height(coin,blocks[n-1].hash2) > coin->blocks.hwmheight-1000 )
iguana_send_hashes(coin,strcmp(coin->name,"bitcoin") != 0 ? "getblocks" : "getheaders",addr,bits256_zero,&blocks[n-1].hash2,1);
}
printf("%s gotheaders.%d height.%d flag.%d\n",addr->ipaddr,n,coin->blocks.hwmheight,flag);
//portable_mutex_unlock(&coin->blocks.mutex);
}*/
//#define IGUANA_OVERLAP 64
//#define IGUANA_MAXWAITING (2 * IGUANA_MAXPEERS * IGUANA_OVERLAP)
//#define IGUANA_EXPIREWINDOW 1000
//#define IGUANA_READAHEAD (IGUANA_EXPIREWINDOW)
#ifndef IGUANA_DEDICATED_THREADS
limit = 1;
if ( addr->ipbits != 0 && addr->pendhdrs < limit && (hashstr= queue_dequeue(&coin->R.hdrsQ,1)) != 0 )
{
decode_hex(hash2.bytes,sizeof(hash2),hashstr);
iguana_send_hashes(coin,strcmp(coin->name,"bitcoin") != 0 ? "getblocks" : "getheaders",addr,bits256_zero,&hash2,1);
queue_enqueue("pendinghdrsQ",&coin->R.pendinghdrsQ[0],(void *)((long)hashstr - sizeof(struct queueitem)),0);
//printf("dequeue hdrsQ.(%s) -> %s pendinghdrsQ\n",hashstr,addr->ipaddr);
addr->hdrmillis = milliseconds();
addr->pendhdrs++;
flag++;
}
if ( addr->recvblocks == 0 )
limit = 1;
else limit = IGUANA_MAXPENDING;
if ( addr->ipbits != 0 && addr->pendblocks < limit && (hashstr= queue_dequeue(&coin->blocksQ,1)) != 0 )
{
//printf("dequeued.(%s) for %s\n",hashstr,addr->ipaddr);
decode_hex(hash2.bytes,sizeof(hash2),hashstr);
if ( memcmp(hash2.bytes,coin->chain->genesis_hashdata,sizeof(hash2)) != 0 )
{
iguana_request_data(coin,addr,&hash2,1,MSG_BLOCK,0);
addr->pendblocks++;
flag++;
}
free_queueitem(hashstr);
}
#endif
void newiguana_updatehdrs(struct iguana_info *coin)
{
int32_t i,j,hdri,flag,iter; char *hashstr; struct iguana_hdrs *hdrs; bits256 hash2;
portable_mutex_lock(&coin->R.hdrsmutex);
if ( iguana_needhdrs(coin) == 0 )
return;
iguana_requesthdrs(coin,0);
return;
hdri = (coin->blocks.hwmheight / IGUANA_HDRSCOUNT);
hdrs = &coin->R.hdrs[hdri];
if ( time(NULL) > coin->R.lasthdrtime+3 && coin->blocks.hwmheight < coin->longestchain-500 )
{
for (iter=flag=0; iter<2; iter++)
{
while ( flag == 0 && (hashstr= queue_dequeue(&coin->R.pendinghdrsQ[iter],1)) != 0 )
{
//printf("timeout found pending.(%s)\n",hashstr);
flag++;
decode_hex(hash2.bytes,sizeof(hash2),hashstr);
for (j=0; j<2; j++)
iguana_send_hashes(coin,strcmp(coin->name,"bitcoin") != 0 ? "getblocks" : "getheaders",0,bits256_zero,&hash2,1);
//queue_enqueue("resubmit",&coin->R.pendinghdrsQ[iter ^ 1],(void *)((long)hashstr - sizeof(struct queueitem)),0);
coin->R.lasthdrtime = (uint32_t)time(NULL);
break;
}
}
if ( hdrs->blocks == 0 && coin->peers.numranked > 2 )
{
hash2 = iguana_blockhash(coin,hdri * IGUANA_HDRSCOUNT);
printf("hdrs backstop %d %s\n",hdri * IGUANA_HDRSCOUNT,bits256_str(hash2));
for (j=0; j<3; j++)
iguana_send_hashes(coin,strcmp(coin->name,"bitcoin") != 0 ? "getblocks" : "getheaders",coin->peers.ranked[j],bits256_zero,&hash2,1);
coin->R.lasthdrtime = (uint32_t)time(NULL);
}
}
if ( coin->blocks.hwmheight > 100000 && coin->R.savedhdrs < coin->blocks.hwmheight-501 )
coin->R.savedhdrs = iguana_savehdrs(coin);
//printf("hdri.%d height.%d n.%d %p coin->R.savedhdrs.%u\n",hdri,hdrs->height,hdrs->n,hdrs->blocks,coin->R.savedhdrs);
if ( hdrs->blocks != 0 && (hdrs->height + hdrs->n) > coin->blocks.hwmheight )
iguana_processhdrs(coin,hdrs->blocks,hdrs->n);
for (i=0; i<hdri; i++)
{
hdrs = &coin->R.hdrs[i];
if ( coin->blocks.hwmheight >= (hdrs->height + hdrs->n) )
{
if ( hdrs->blocks != 0 )
{
myfree(hdrs->blocks,hdrs->n * sizeof(*hdrs->blocks));
hdrs->blocks = 0;
}
if ( hdrs->conflictblocks != 0 )
{
myfree(hdrs->conflictblocks,hdrs->n * sizeof(*hdrs->conflictblocks));
hdrs->conflictblocks = 0;
}
}
}
portable_mutex_unlock(&coin->R.hdrsmutex);
}
void iguana_gotheadersM(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_block *blocks,int32_t n)
{
int32_t i,iter,flag; char hexstr[65],*hashstr;
addr->lastrequest = bits256_zero;
addr->recvhdrs++;
if ( addr->pendhdrs > 0 )
addr->pendhdrs--;
coin->R.lasthdrtime = (uint32_t)time(NULL);
iguana_processhdrs(coin,blocks,n);
return;
//printf("hdrs.(%s) n.%d from %s\n",bits256_str(blocks[0].hash2),n,addr->ipaddr);
portable_mutex_lock(&coin->R.hdrsmutex);
for (i=0; i<coin->R.numhdrs; i++)
{
if ( memcmp(coin->R.hdrs[i].hash2.bytes,blocks[0].prev_block.bytes,sizeof(bits256)) == 0 )
{
init_hexbytes_noT(hexstr,blocks[0].prev_block.bytes,sizeof(bits256));
for (iter=flag=0; iter<2; iter++)
{
while ( flag == 0 && (hashstr= queue_dequeue(&coin->R.pendinghdrsQ[iter],1)) != 0 )
{
if( strcmp(hashstr,hexstr) == 0 )
{
free_queueitem(hashstr);
//printf("found pending.(%s) hdri.%d\n",hexstr,(coin->blocks.hwmheight / IGUANA_HDRSCOUNT));
flag++;
break;
}
queue_enqueue("requeue",&coin->R.pendinghdrsQ[iter ^ 1],(void *)((long)hashstr - sizeof(struct queueitem)),0);
}
}
if ( coin->R.hdrs[i].blocks == 0 )
{
coin->R.hdrs[i].blocks = blocks;
coin->R.hdrs[i].n = n;
printf("got headers for %d[%d] from %s\n",coin->R.hdrs[i].height,n,addr->ipaddr);
if ( addr != 0 && coin->R.hdrs[i].height+n > addr->height )
addr->height = coin->R.hdrs[i].height+n;
}
else if ( coin->R.hdrs[i].n == n && memcmp(coin->R.hdrs[i].blocks,blocks,n*sizeof(*blocks)) == 0 )
{
coin->R.hdrs[i].duplicates++;
printf("duplicate.%d blocks for height.%d n.%d\n",coin->R.hdrs[i].duplicates,coin->R.hdrs[i].height,n);
myfree(blocks,sizeof(*blocks) * n);
}
else
{
if ( coin->R.hdrs[i].conflictblocks != 0 )
{
myfree(coin->R.hdrs[i].conflictblocks,coin->R.hdrs[i].conflictblocksn * sizeof(struct iguana_block));
}
coin->R.hdrs[i].conflicts++;
printf("conflict.%d blocks for height.%d n.%d\n",coin->R.hdrs[i].conflicts,coin->R.hdrs[i].height,n);
coin->R.hdrs[i].conflictblocks = blocks;
coin->R.hdrs[i].conflictblocksn = n;
}
portable_mutex_unlock(&coin->R.hdrsmutex);
return;
}
}
printf("got unexpected hdrs[%d] prev %s\n",n,bits256_str(blocks[0].prev_block));
myfree(blocks,sizeof(*blocks) * n);
portable_mutex_unlock(&coin->R.hdrsmutex);
}
void iguana_connections(void *arg)
{
FILE *fp; uint8_t serialized[sizeof(struct iguana_msghdr)]; struct iguana_info *coin,**coins = arg;
int32_t i,j,r,n,iter,flag; uint32_t now,lastrank; char fname[512];
struct iguana_peer *addr;
n = (int32_t)coins[0];
lastrank = (uint32_t)time(NULL);
coins++;
for (i=0; i<n; i++)
{
coin = coins[i];
for (iter=0; iter<2; iter++)
{
sprintf(fname,"%s_%s.txt",coin->symbol,(iter == 0) ? "peers" : "hdrs");
if ( (fp= fopen(fname,"r")) != 0 )
iguana_parseline(coin,iter,fp);
fclose(fp);
}
//iguana_recvinit(coin,coin->R.numwaitingbits);
}
while ( 1 )
{
if ( time(NULL) > lastrank+60 )
{
for (i=0; i<n; i++)
{
portable_mutex_lock(&coin->peers.mutex);
iguana_peermetrics(coins[i]);
portable_mutex_unlock(&coin->peers.mutex);
}
lastrank = (uint32_t)time(NULL);
}
now = (uint32_t)time(NULL);
for (i=flag=0; i<n; i++)
{
if ( (coin= coins[i]) != 0 )
{
r = rand();
for (j=0; j<IGUANA_MAXPEERS; j++)
{
addr = &coin->peers.active[(j + r) % IGUANA_MAXPEERS];
if ( addr->usock >= 0 && addr->ipbits != 0 )
{
if ( addr->dead == 0 && addr->ready > 0 )
{
if ( now > addr->lastblockrecv+60 && addr->pendblocks > 0 )
addr->pendblocks--;
if ( now > coin->peers.lastpeer+300 )
iguana_queue_send(coin,addr,serialized,"getaddr",0,0,0);
}
//printf("%s pend.(%d %d) dead.%u ready.%u relay.%d millis.%.0f hwm.%d\n",addr->ipaddr,addr->pendhdrs,addr->pendblocks,addr->dead,addr->ready,addr->relayflag,addr->hdrmillis,coin->blocks.hwmheight);
}
}
if ( now > coin->peers.lastpeer+300 )
{
printf("lastpeer %u vs now.%u, startpeers\n",coin->peers.lastpeer,now);
coin->peers.lastpeer = now;
}
}
iguana_shutdownpeers(coin,0); // closes dead peers to free up open spots
}
if ( flag == 0 )
usleep(10000);
}
}
&& ((packet= queue_dequeue(&addr->sendQ,0)) != 0 || (packet= queue_dequeue(&coin->sendQ,0)) != 0) )
{
//printf("%d %s: usock.%d dead.%u ready.%u\n",i,addr->ipaddr,addr->usock,addr->dead,addr->ready);
flag++;
if ( (packet->addr != 0 && packet->addr != addr) || (packet->getdatablock > 0 && packet->getdatablock < coin->blocks.parsedblocks) || coin->R.recvblocks[packet->getdatablock] != 0 )
{
if ( coin->R.recvblocks[packet->getdatablock] == 0 )
printf("peerloop: (%s).%d packetaddr.%p != %p || packet->getdatablock %d < %d coin->blocks.parsedblocks recv[%p]\n",packet->serialized+4,packet->datalen,packet->addr,addr,packet->getdatablock,coin->blocks.parsedblocks,coin->R.recvblocks[packet->getdatablock]);
myfree(packet,sizeof(*packet) + packet->datalen);
}
else
{
if ( 1 && addr != coin->peers.localaddr )
{
if ( )
{
addr->startsend = (uint32_t)time(NULL);
strcpy(addr->symbol,coin->symbol);
strcpy(addr->coinstr,coin->name);
iguana_launch("send_data",iguana_issue,packet,IGUANA_SENDTHREAD);
} else printf("need to wait for pending sends %d\n",iguana_numthreads(1<<IGUANA_SENDTHREAD));
}
else //if ( addr != 0 )
{
iguana_send(coin,addr,packet->serialized,packet->datalen);
if ( packet->getdatablock > 0 )
iguana_setwaitstart(coin,packet->getdatablock);
myfree(packet,sizeof(*packet) + packet->datalen);
}
}
void iguana_queuehdrs(struct iguana_info *coin,int32_t height,bits256 hash2)
{
char hashstr[65]; //int32_t hdrsi;
init_hexbytes_noT(hashstr,hash2.bytes,sizeof(hash2));
queue_enqueue("hdrsQ",&coin->R.hdrsQ,queueitem(hashstr),1);
//printf("try to queue hdr.(%s) height.%d vs %d\n",hashstr,height,coin->blocks.hwmheight);
/*if ( (height % IGUANA_HDRSCOUNT) == 0 && height+1 >= coin->blocks.hwmheight )
{
hdrsi = (height / IGUANA_HDRSCOUNT);
if ( (height == 0 || coin->R.hdrs[hdrsi].height == 0) && coin->R.hdrs[hdrsi].duplicates == 0 )
{
coin->R.hdrs[hdrsi].hash2 = hash2;
coin->R.hdrs[hdrsi].height = height;
if ( hdrsi >= coin->R.numhdrs )
coin->R.numhdrs = hdrsi + 1;
//printf("queued hdr.(%s)\n",hashstr);
queue_enqueue("hdrsQ",&coin->R.hdrsQ,queueitem(hashstr),1);
}
}*/
}
int32_t iguana_queue_send(struct iguana_info *coin,struct iguana_peer *addr,uint8_t *serialized,char *cmd,int32_t len,int32_t getdatablock,int32_t forceflag)
{
struct iguana_packet *packet; int32_t datalen;
if ( addr == 0 )
{
printf("iguana_queue_send null addr\n");
getchar();
return(-1);
}
datalen = iguana_sethdr((void *)serialized,coin->chain->netmagic,cmd,&serialized[sizeof(struct iguana_msghdr)],len);
if ( strcmp("getaddr",cmd) == 0 && time(NULL) < addr->lastgotaddr+300 )
return(0);
if ( strcmp("version",cmd) == 0 )
return(iguana_send(coin,addr,serialized,datalen));
packet = mycalloc('S',1,sizeof(struct iguana_packet) + datalen);
packet->datalen = datalen;
packet->addr = addr;
if ( 1 && (packet->getdatablock = getdatablock) == 0 && strcmp((char *)&serialized[4],"getdata") == 0 )
{
printf("no need to request genesis\n");
getchar();
}
memcpy(packet->serialized,serialized,datalen);
//printf("%p queue send.(%s) %d to (%s) %x\n",packet,serialized+4,datalen,addr->ipaddr,addr->ipbits);
queue_enqueue("sendQ",addr != 0 ? &addr->sendQ : &coin->sendQ,&packet->DL,0);
//printf("queue send.(%s) datalen.%d addr.%p %s [%d]\n",cmd,len,addr,addr!=0?addr->ipaddr:"",getdatablock);
if ( addr == 0 || (addr->dead == 0 && addr->ipbits != 0) )
{
if ( addr == 0 && getdatablock == 0 )
addr = iguana_choosepeer(coin);
if ( addr == coin->peers.localaddr || (getdatablock == 0 && strcmp(cmd,"getdata") != 0) )
forceflag = 1;
if ( forceflag != 0 )
{
if ( getdatablock >= coin->blocks.parsedblocks )
len = iguana_send(coin,addr!=0?addr:iguana_choosepeer(coin),serialized,datalen);
else len = -1;
}
else
{
packet = mycalloc('S',1,sizeof(struct iguana_packet) + datalen);
packet->datalen = datalen;
packet->addr = addr;
if ( 1 && (packet->getdatablock = getdatablock) == 0 && strcmp((char *)&serialized[4],"getdata") == 0 )
{
printf("no need to request genesis\n");
getchar();
}
memcpy(packet->serialized,serialized,datalen);
//printf("%p queue send.(%s) %d to (%s) %x\n",packet,serialized+4,datalen,addr->ipaddr,addr->ipbits);
queue_enqueue("sendQ",addr != 0 ? &addr->sendQ : &coin->sendQ,&packet->DL,0);
}
} else printf("cant send.(%s) len.%d datalen.%d to null addr or dead.%u\n",&serialized[4],len,datalen,addr->dead);
return(len);
}
while ( (packet= queue_dequeue(&addr->sendQ,0)) != 0 )
{
if ( packet->getdatablock > 0 && packet->getdatablock < coin->blocks.parsedblocks )
{
packet->addr = 0;
printf("recycle pending sendQ block.%d\n",packet->getdatablock);
queue_enqueue("shutdown_sendQ",&coin->blocksQ,&packet->DL,0);
} else myfree(packet,sizeof(*packet) + packet->datalen);
}
void iguana_dedicatedrecv(void *arg)
{
struct iguana_info *coin = 0; uint8_t *buf; int32_t bufsize; struct iguana_peer *addr = arg;
if ( addr == 0 || (coin= iguana_coin(addr->symbol)) == 0 )
{
printf("iguana_dedicatedrecv nullptrs addr.%p coin.%p\n",addr,coin);
return;
}
printf("DEDICATED RECV %s\n",addr->ipaddr);
bufsize = IGUANA_MAXPACKETSIZE;
buf = mycalloc('r',1,bufsize);
while ( addr->usock >= 0 && addr->dead == 0 && coin->peers.shuttingdown == 0 )
_iguana_processmsg(coin,addr,buf,bufsize);
myfree(buf,bufsize);
}
if ( packet->getdatablock > 0 && (packet->getdatablock < coin->blocks.parsedblocks || coin->R.recvblocks[packet->getdatablock] != 0) )
{
printf("discard sendQ for getdatablock.%d parsed.%d\n",packet->getdatablock,coin->blocks.parsedblocks);
myfree(packet,sizeof(*packet) + packet->datalen);
return(1);
void iguana_issue(void *ptr)
{
uint32_t ipbits; char ipaddr[64]; struct iguana_peer *addr; struct iguana_info *coin=0; struct iguana_packet *packet = ptr;
if ( (addr= packet->addr) == 0 || (coin= iguana_coin(addr->symbol)) == 0 || addr->dead != 0 )
{
printf("iguana_issue: addr %p coin.%p dead.%u\n",addr,coin,addr->dead);
return;
}
ipbits = (uint32_t)calc_ipbits(addr->ipaddr);
expand_ipbits(ipaddr,ipbits);
if ( strcmp(ipaddr,addr->ipaddr) == 0 )
{
if ( packet->getdatablock == 0 )
iguana_send(coin,addr,packet->serialized,packet->datalen);
else if ( packet->getdatablock > 0 && packet->getdatablock >= coin->blocks.parsedblocks )
{
//printf("req block.%d to (%s) numthreads.%d\n",packet->getdatablock,packet->addr->ipaddr,iguana_numthreads(1 << IGUANA_SENDTHREAD));
iguana_send(coin,addr,packet->serialized,packet->datalen);
iguana_setwaitstart(coin,packet->getdatablock);
}
}
else printf("iguana_issue: ipaddr mismatch.(%s) != (%s)\n",ipaddr,addr->ipaddr), getchar();
//printf("finished sending %d to (%s) numthreads.%d\n",packet->datalen,packet->addr->ipaddr,iguana_numthreads(-1));
addr->startsend = 0;
myfree(packet,sizeof(*packet) + packet->datalen);
}
uint64_t iguana_validaterecv(struct iguana_info *coin,int32_t *nump,char *fname)
{
struct iguana_pending *ptr; struct iguana_block space; struct iguana_msgtx *tx;
int32_t n = 0; struct iguana_mappedptr M; struct iguana_memspace RSPACE; uint64_t allocated = 0;
memset(&M,0,sizeof(M));
memset(&RSPACE,0,sizeof(RSPACE));
if ( (ptr= iguana_mappedptr(0,&M,0,0,fname)) != 0 )
{
RSPACE.ptr = M.fileptr;
RSPACE.used = 0;
RSPACE.size = M.allocsize;
printf("process.(%s) %ld\n",fname,(long)M.allocsize);
n = 0;
while ( ptr != 0 && ((long)ptr - (long)RSPACE.ptr)+ptr->next < (RSPACE.size - sizeof(*ptr)) )
{
//printf("ptr diff.%d next.%d\n",(int32_t)((long)ptr - (long)RSPACE.ptr),ptr->next);
if ( (tx= iguana_validpending(coin,ptr,&space)) != 0 )
{
//printf("%d: ht.%-6d size.%d next.%d\n",n,ptr->block.height,ptr->allocsize,ptr->next);
iguana_freetx(tx,ptr->numtx);
allocated += ptr->allocsize;
n++;
coin->R.recvblocks[ptr->block.height] = ptr;
}
else
{
printf("n.%d ht.%d: tx doesnt validate\n",n,ptr->block.height);
}
if ( ptr->next != 0 )
ptr = (void *)((long)ptr + ptr->next);
else break;
}
if ( n == 0 )
iguana_closemap(&M);
}
*nump = n;
return(allocated);
}
for (i=maxi=skipped=total=0; skipped<10; i++)
{
if ( coin->R.maprecvdata == 0 )
break;
sprintf(fname,"tmp/%s/recv.%d",coin->symbol,i), iguana_compatible_path(fname);
if ( (allocated= iguana_validaterecv(coin,&n,fname)) != 0 )
combined += allocated, total += n, skipped = 0, maxi = i;
else if ( skipped++ > 10 )
break;
}
/*for (i=0; i<n; i++)
{
coin = coins[1 + i];
sprintf(dirname,"DB/%s",coin->symbol);
ensure_directory(dirname);
sprintf(dirname,"tmp/%s",coin->symbol);
ensure_directory(dirname);
}*/
//iguana_launch("peers",iguana_connections,coins,IGUANA_PERMTHREAD);
//iguana_launch("requests",iguana_requests,coins,IGUANA_PERMTHREAD);
//portable_mutex_t hdrsmutex; struct iguana_hdrs *hdrs; uint32_t savedhdrs,lasthdrtime,numhdrs;
struct iguana_hdrs
{
bits256 hash2;
struct iguana_block *blocks,*conflictblocks;
int32_t n,conflictblocksn,height,conflicts,duplicates;
};
bits256 iguana_unspentmap(struct iguana_info *coin,uint32_t *spendindp,uint32_t *txidindp,char *txidstr,uint32_t unspentind)
{
struct iguana_unspent U;
memset(&U,0,sizeof(U));
if ( iguana_rwunspentind(coin,0,&U,unspentind) == 0 )
{
*txidindp = U.txidind;
*spendindp = U.spendind;
if ( txidstr != 0 )
return(iguana_txidstr(coin,0,0,txidstr,U.txidind));
}
else printf("error getting unspents[%u] when %d\n",unspentind,coin->latest.numunspents), getchar();
return(bits256_zero);
}
int32_t iguana_inittxid(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,int32_t itemind,int32_t itemsize,int32_t numitems)
{
char txidstr[513]; bits256 checktxid; uint32_t txidind,spendind; struct iguana_txid *tx = value;
if ( key != 0 && value != 0 && itemind > 0 )
{
//printf("inittxid.(%s) itemind.%d (%d %d)\n",bits256_str(tx->txid),itemind,tx->firstvout,tx->firstvin);
checktxid = iguana_unspentmap(coin,&spendind,&txidind,txidstr,tx->firstvout);
if ( memcmp(checktxid.bytes,key,sizeof(checktxid)) != 0 || txidind != itemind )
{
printf("checktxid.%s miscompares to %s, txidind.%d vs itemind.%d\n",txidstr,bits256_str(tx->txid),txidind,itemind);
getchar();
return(-1);
}
if ( spendind >= coin->latest.numspends )
{
//struct iguana_unspent U;
//iguana_rwunspentind(coin,0,&U,tx->firstvout);
//U.spendind = 0;
//iguana_rwunspentind(coin,1,&U,tx->firstvout);
printf("spendind.%d vs %d overflow in txid.%s txidind.%d U%d autocleared\n",spendind,coin->latest.numspends,txidstr,tx->firstvout,tx->firstvout);
}
//printf("txidind.%d: 1st.(%d %d)\n",txidind,tx->firstvout,tx->firstvin);
}
return(0);
}
/*if ( flag != 0 && height > 0 )
{
if ( coin->latest.numtxids != lastblock.L.firsttxidind + lastblock.txn_count && iguana_kvtruncate(coin,coin->txids,lastblock.L.firsttxidind + lastblock.txn_count) < 0 )
err |= 1;
if ( coin->latest.numunspents != lastblock.L.firstvout + lastblock.numvouts && iguana_kvtruncate(coin,coin->unspents,lastblock.L.firstvout + lastblock.numvouts) < 0 )
err |= 2;
if ( coin->latest.numspends != lastblock.L.firstvin + lastblock.numvins && iguana_kvtruncate(coin,coin->spends,lastblock.L.firstvin + lastblock.numvins) < 0 )
err |= 4;
if ( coin->latest.numpkhashes != lastblock.L.numpkinds && iguana_kvtruncate(coin,coin->pkhashes,lastblock.L.numpkinds) < 0 )
err |= 8;
}
else
{
printf("reset counters flag.%d height.%d\n",flag,height); //getchar();
}
if ( err != 0 )
return(-err);*/
checktxid = iguana_txidstr(coin,0,0,txidstr,txidind);
if ( memcmp(checktxid.bytes,txid.bytes,sizeof(txid)) != 0 )
{
int32_t i;
printf("error kvwrite/read of txid.%s vs %s txidind.%d\n",bits256_str(txid),bits256_str2(checktxid),txidind);
for (i=-10; i<10; i++)
{
iguana_rwtxidind(coin,0,&tx,txidind+i);
printf("txidind.%d %s\n",txidind+i,bits256_str(tx.txid));
}
getchar();
return(0);
}
checkind = iguana_txidind(coin,&checkfirstvout,&checkfirstvin,txid);
if ( checkind != txidind || checkfirstvout != firstvout || checkfirstvin != firstvin )
{
printf("error kvwrite/read of txidind.%d:%d %s firstvout.%d vs %d firstvin.%d vs %d\n",txidind,checkind,bits256_str(txid),firstvout,checkfirstvout,checkfirstvin,firstvin);
getchar();
return(0);
}
int32_t iguana_recvinit(struct iguana_info *coin,int32_t initialheight)
{
//int32_t maxi,total; uint64_t allocated,combined = 0;
//portable_mutex_init(&coin->R.RSPACE.mutex);
//memset(&coin->R.RSPACE,0,sizeof(coin->R.RSPACE));
//coin->R.RSPACE.size = 1024*1024*128;
//coin->R.RSPACE.counter = total != 0 ? maxi+1 : 0;
return(0);
}
int32_t iguana_initpkhash(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,int32_t itemind,int32_t itemsize,int32_t numitems)
{
int64_t balance; uint64_t credits,debits; int32_t numutxo; uint32_t unspents[64]; struct iguana_pkhash *P = value;
if ( key != 0 && value != 0 && itemind > 0 )
{
if ( (balance= iguana_balance(coin,&credits,&debits,&numutxo,unspents,sizeof(unspents)/sizeof(*unspents),P,itemind)) < 0 )
{
printf("iguana_balance error pkind.%d %.8f vs %.8f\n",itemind,dstr(balance),dstr(P->balance));
getchar();
return(-1);
}
coin->latest.credits += credits;
coin->latest.debits += debits;
}
return(0);
}
/*
int64_t iguana_balance(struct iguana_info *coin,uint64_t *creditsp,uint64_t *debitsp,int32_t *nump,uint32_t *unspents,long max,struct iguana_pkhash *P,uint32_t pkind)
{
uint32_t unspentind,spendind,lastunspentind,lastspendind,flag,n = 0; int64_t credits,debits,net = 0;
struct iguana_unspent U; struct iguana_spend S;
*creditsp = *debitsp = net = credits = debits = lastunspentind = lastspendind = flag = 0;
unspentind = P->firstunspentind;
while ( unspentind > 0 )
{
lastunspentind = unspentind;
if ( iguana_rwunspentind(coin,0,&U,unspentind) == 0 )
{
credits += U.value;
if ( U.spendind == 0 )
{
net += U.value;
if ( n < max && unspents != 0 )
unspents[n] = unspentind;
}
n++;
if ( unspentind != P->lastunspentind && U.nextunspentind > 0 && U.nextunspentind > unspentind && U.nextunspentind < coin->latest.numunspents )
unspentind = U.nextunspentind;
else
{
if ( U.nextunspentind == 0 ) // cleared during unspents init
{
P->lastunspentind = unspentind = lastunspentind;
flag++;
}
break;
}
} else return(-1);
}
if ( unspentind == P->lastunspentind )
{
if ( (spendind= P->firstspendind) >= coin->latest.numspends )
{
P->firstspendind = P->lastspendind = spendind = 0;
flag++;
}
while ( spendind > 0 )
{
lastspendind = spendind;
if ( iguana_rwspendind(coin,0,&S,spendind) == 0 )
{
if ( S.unspentind > 0 && S.unspentind < coin->latest.numunspents && iguana_rwunspentind(coin,0,&U,S.unspentind) == 0 )
{
debits += U.value;
if ( spendind != P->lastspendind && S.nextspendind > 0 && S.nextspendind > spendind && S.nextspendind < coin->latest.numspends )
spendind = S.nextspendind;
} else S.nextspendind = 0;
if ( S.nextspendind == 0 ) // cleared during spends init
{
P->lastspendind = spendind = lastspendind;
flag++;
break;
}
} else return(-1);
}
if ( flag != 0 )
{
if ( iguana_rwpkind(coin,1,P,pkind) < 0 )
printf("error ");
printf("pkind.%d autofix\n",pkind);
P->balance = (credits - debits);
}
if ( net != (credits - debits) )
printf("iguana_balance: total mismatch %.8f != %.8f (%.8f - %.8f)\n",dstr(net),dstr(credits)-dstr(debits),dstr(credits),dstr(debits));
*nump = n;
*creditsp = credits;
*debitsp = debits;
return(net);
} else printf("iguana_balance error: unspentind.%u != last.%u\n",unspentind,P->lastunspentind);
*nump = 0;
return(-1);
}*/
int32_t iguana_processhdrs(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_block *blocks,int32_t n)
{
bits256 hash2; int32_t i,flag=0,startheight = -1,height = -1; struct iguana_block space,*block;
if ( startheight >= 0 )
{
printf("%s received headers %d [%d] %s\n",addr->ipaddr,startheight,n,bits256_str(blocks[0].hash2));
if ( startheight+n < coin->blocks.hwmheight )
return(-1);
for (i=0; i<n; i++)
{
if ( (height= startheight+i) < coin->blocks.hwmheight )
continue;
if ( (block= iguana_findblock(coin,&space,blocks[i].hash2)) == 0 || height > coin->blocks.hwmheight )
{
if ( (height= iguana_addblock(coin,blocks[i].hash2,&blocks[i])) > 0 )
{
iguana_gotdata(coin,0,blocks[i].height,blocks[i].hash2);
flag++;
}
} else printf("height.%d:%d %s block.%p flag.%d\n",height,blocks[i].height,bits256_str(blocks[i].hash2),block,flag);
}
if ( flag != 0 )
{
//iguana_queuehdrs(coin,blocks[n-1].height,blocks[n-1].hash2,1);
//iguana_lookahead(coin,&hash2,coin->blocks.hwmheight + 1);
}
}
iguana_lookahead(coin,&hash2,coin->blocks.hwmheight + 1);
return(flag);
}
/*int32_t iguana_updatewaiting(struct iguana_info *coin,int32_t starti,int32_t max)
{
int32_t i,height,gap,n = 0; uint32_t now;
now = (uint32_t)time(NULL);
height = starti;
for (i=0; i<max; i++,height++)
{
gap = (height - coin->blocks.parsedblocks);
if ( gap >= 0 )
gap = sqrt(gap);
if ( gap < 1 )
gap = 1;
if ( height < coin->R.numwaitingbits && coin->R.recvblocks[height] == 0 && now > (coin->R.waitstart[height] + gap) )
{
//printf("restart height.%d width.%d widthready.%d %s\n",height,coin->width,coin->widthready,bits256_str(iguana_blockhash(coin,height)));
iguana_waitclear(coin,height);
iguana_waitstart(coin,height);
} //else printf("%d %d %p %u\n",height,coin->R.numwaitingbits,coin->R.recvblocks[height],coin->R.waitstart[height]);
}
//printf("height.%d max.%d\n",starti,max);
height = starti;
for (i=0; i<max; i++,height++)
if ( coin->R.recvblocks[height] != 0 )
n++;
return(n);
}*/
/*void iguana_queuehdrs(struct iguana_info *coin,int32_t height,bits256 hash2,int32_t forceflag)
{
char hashstr[65];
if ( memcmp(bits256_zero.bytes,hash2.bytes,sizeof(hash2)) == 0 )
{
printf("trying to queue null hash\n");
getchar();
}
if ( height < 0 )
forceflag = 1;
if ( (forceflag != 0 && height > coin->blocks.hwmheight-coin->chain->bundlesize) || (height/coin->chain->bundlesize) > (coin->R.topheight/coin->chain->bundlesize) )
{
printf("queue hdrs height.%d %s\n",height,bits256_str(hash2));
coin->R.pendingtopheight = coin->R.topheight;
coin->R.pendingtopstart = (uint32_t)time(NULL);
init_hexbytes_noT(hashstr,hash2.bytes,sizeof(hash2));
queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1);
}
}*/
/*if ( block->height >= coin->blocks.parsedblocks )
{
memset(&space,0,sizeof(space));
if ( iguana_kvread(coin,coin->blocks.db,0,&space,(uint32_t *)&block->height) != 0 )
iguana_mergeblock(&space,block);
else printf("iguana_gotblock: cant read block.%d\n",block->height);
iguana_recvblock(coin,addr,&space,txarray,numtx,data,datalen);
iguana_kvwrite(coin,coin->blocks.db,0,&space,(uint32_t *)&space.height);
} // else printf("orphan %d block.%s from gotblockM\n",block->height,bits256_str(block->hash2));
iguana_waitclear(coin,block->height);*/
//portable_mutex_unlock(&coin->blocks.mutex);
/*if ( 1 && coin->R.pendingtopheight == 0 )
{
for (checkpointi=coin->blocks.hwmheight/coin->chain->bundlesize; checkpointi<coin->R.numcheckpoints; checkpointi++)
if ( memcmp(bits256_zero.bytes,coin->R.checkpoints[checkpointi].prevhash2.bytes,sizeof(coin->R.checkpoints[checkpointi])) != 0 )
iguana_queuehdrs(coin,coin->R.checkpoints[checkpointi].height,coin->R.checkpoints[checkpointi].prevhash2,1);
coin->R.pendingtopheight = 1;
printf("issued initial gethdrs from %d\n",(coin->blocks.hwmheight/coin->chain->bundlesize)*coin->chain->bundlesize); //getchar();
}
if ( coin->R.topheight < 0 )
coin->R.topheight = 0;
if ( coin->blocks.hwmheight < 0 )
coin->blocks.hwmheight = 0;
if ( coin->R.topheight < coin->blocks.hwmheight )
coin->R.topheight = coin->blocks.hwmheight;
if ( coin->R.topheight == 0 || coin->R.topheight >= coin->R.pendingtopheight+coin->chain->bundlesize || time(NULL) > (coin->R.lasthdrtime + 60) )
{
memset(hash2.bytes,0,sizeof(hash2));
if ( coin->R.pendingtopheight != coin->R.topheight )
{
height = (coin->R.topheight/coin->chain->bundlesize) * coin->chain->bundlesize;
hash2 = coin->R.checkpoints[height / coin->chain->bundlesize].prevhash2;
printf("request new header %d vs %d %u %s\n",height,coin->R.topheight,coin->R.pendingtopstart,bits256_str(hash2));
if ( memcmp(bits256_zero.bytes,hash2.bytes,sizeof(hash2)) == 0 )
hash2 = iguana_blockhash(coin,height);
}
if ( memcmp(bits256_zero.bytes,hash2.bytes,sizeof(hash2)) == 0 )
{
iguana_lookahead(coin,&hash2,1);
if ( coin->blocks.hwmheight < coin->blocks.parsedblocks )
coin->blocks.parsedblocks = coin->blocks.hwmheight;
height = coin->blocks.parsedblocks;
hash2 = iguana_blockhash(coin,height);
if ( iguana_choosepeer(coin) != 0 )
printf("hwmchain request new header %d vs %d %u\n",coin->R.pendingtopheight,coin->R.topheight,coin->R.pendingtopstart);
}
coin->R.lasthdrtime = (uint32_t)time(NULL);
if ( memcmp(bits256_zero.bytes,hash2.bytes,sizeof(hash2)) != 0 )
{
iguana_queuehdrs(coin,height,hash2,1);
return(1);
}
}
if ( coin->newhdrs != 0 )
{
coin->newhdrs = 0;
height = coin->blocks.hwmheight;
iguana_lookahead(coin,&hash2,height + 1);
if ( coin->blocks.hwmheight > height )
return(1);
}*/
/*for (iter=0; iter<2; iter++)
{
while ( (req= queue_dequeue(&addr->pendblocksQ[iter ^ 1],0)) != 0 )
{
if ( memcmp(&req->hash2,hash2.bytes,sizeof(hash2)) == 0 )
{
if ( (*heightp= req->height) >= 0 && req->checkpointi >= 0 )
{
printf("FOUND.(%s) height.%d\n",bits256_str(req->hash2),req->height);
if ( deleteflag == 0 )
queue_enqueue("pendblocksQ",&addr->pendblocksQ[iter ^ 1],&req->DL,0);
return(&coin->R.checkpoints[req->checkpointi]);
} else printf("height.%d checkpointi.%d\n",req->height,req->checkpointi);
}
printf("requeue.%p\n",req);
queue_enqueue("pendblocksQ",&addr->pendblocksQ[iter ^ 1],&req->DL,0);
}
}
return(0);*/
void iguana_queuebundle(struct iguana_info *coin,struct iguana_bundle *bundle)
{
int32_t i;
printf("queue bundle.%p %s height.%d num.%d waitingbits.%d\n",bundle,bits256_str(bundle->prevhash2),bundle->height,bundle->num,coin->R.numwaitingbits);
for (i=0; i<bundle->num; i++)
{
//printf("bundle[i.%d] %d %s\n",i,bundle->height + 1 + i,bits256_str(bundle->blocks[i].hash2));
if ( iguana_recvblock(coin,bundle->height + 1 + i) == 0 )
{
coin->R.blockhashes[bundle->height + 1 + i] = bundle->blocks[i].hash2;
//iguana_queueblock(coin,bundle->height + 1 + i,bundle->blocks[i].hash2,0);
}
}
}
struct iguana_bundle *iguana_bundleheight(struct iguana_info *coin,int32_t *heightp,bits256 hash2,bits256 prev_block,int32_t deleteflag)
{
//int32_t i,j,miscompare = 0; struct iguana_bundle *bundle;
*heightp = -1;
/* for (i=0; i<coin->R.numbundles; i++)
{
if ( i*coin->chain->bundlesize > coin->longestchain )
{
// printf("i.%d %d < longestchain.%d\n",i,i*coin->chain->bundlesize,coin->longestchain);
break;
}
bundle = &coin->R.bundles[i];
if ( bundle->height >= 0 && bundle->blocks != 0 )
{
if ( bundle->recvstart == 0 )
continue;
// printf("bundlei.%d recvstart.%u finish.%u\n",i,bundle->recvstart,bundle->recvfinish);
if ( memcmp(bundle->prevhash2.bytes,prev_block.bytes,sizeof(prev_block)) == 0 )
{
*heightp = bundle->height + 1;
return(bundle);
}
for (j=0; j<bundle->num; j++)
{
if ( memcmp(bundle->blocks[j].hash2.bytes,hash2.bytes,sizeof(hash2)) == 0 )
{
*heightp = bundle->height + 1 + j;
//printf("height.%d j.%d (%s) vs (%s) bundle.%d\n",*heightp,j,bits256_str(bundle->blocks[j].hash2),bits256_str2(hash2),bundle->height);
return(bundle);
} else miscompare++;//, printf("%x ",(uint32_t)bundle->blocks[j].hash2.uints[7]);
}
} //else printf("skip bundle.%d %p\n",bundle->height,bundle->blocks);
}
printf("cant find.(%s) miscompares.%d %x\n",bits256_str(hash2),miscompare,(uint32_t)hash2.uints[7]);*/
return(0);
}
/*
static bits256 lasthash2;
struct iguana_blockreq *req; int32_t height;
addr->lastrequest = bits256_zero;
addr->recvhdrs++;
if ( addr->pendhdrs > 0 )
addr->pendhdrs--;
coin->R.lasthdrtime = (uint32_t)time(NULL);
if ( memcmp(lasthash2.bytes,blockhashes[0].bytes,sizeof(lasthash2)) != 0 )
{
if ( n <= 2 )
{
printf("gotblockhashes[%d] %s pend.%d\n",n,bits256_str(blockhashes[0]),addr->pendhdrs);
lasthash2 = blockhashes[0];
}
}
if ( n > 2 )
{
if ( n > coin->chain->bundlesize )
printf("warning: %s gotheaders.%d is too many vs. %d\n",coin->symbol,n,coin->chain->bundlesize);
req = mycalloc('r',1,sizeof(*req));
req->hash2 = blockhashes[0];
req->blockhashes = blockhashes;
req->n = n;
iguana_bundleheight(coin,&height,blockhashes[0],bits256_zero,0);
if ( req->height >= 0 )
{
req->bundlei = (req->height / coin->chain->bundlesize);
//printf("blocksQ.%s height.%d\n",bits256_str(blockhashes[0]),height);
//queue_enqueue("blocksQ",&coin->blocksQ,&req->DL,0);
}
else
{
req->bundlei = -1;
//printf("priorityQ.%s height.%d\n",bits256_str(blockhashes[0]),height);
//queue_enqueue("priorityQ",&coin->priorityQ,&req->DL,0);
}
printf("blocksQ.%s height.%d req->height.%d\n",bits256_str(blockhashes[0]),height,req->height);
queue_enqueue("blocksQ",&coin->blocksQ,&req->DL,0);
} else myfree(blockhashes,n * sizeof(*blockhashes));
}
int32_t h,i,height; uint32_t now; bits256 prevhash2; //char hashstr[65];
struct iguana_blockreq *req; struct iguana_bundle *bundle;
iguana_gotdata(coin,addr,block->height,block->hash2);
now = (uint32_t)time(NULL);
bundle = iguana_bundleheight(coin,&height,block->hash2,block->prev_block,1);
//printf("%s got block.%d height.%d\n",addr!=0?addr->ipaddr:"local",block->height,height);
if ( (req= queue_dequeue(&addr->pendingQ,0)) != 0 ) // should only have depth 1!
{
if ( memcmp(req->hash2.bytes,block->hash2.bytes,sizeof(req->hash2)) == 0 )
{
if ( req->blockhashes != 0 )
{
iguana_gotdata(coin,addr,block->height,block->hash2);
iguana_bundleinit(coin,block->height-1,block->prev_block);
if ( (bundle= iguana_bundle(coin,block->prev_block)) != 0 )
{
portable_mutex_lock(&bundle->mutex);
if ( bundle->blocks == 0 )
{
bundle->blockhashes = req->blockhashes;
bundle->num = req->n;
bundle->bundlei = (block->height / coin->chain->bundlesize);
bundle->firsthash2 = block->hash2;
bundle->lasthash2 = req->blockhashes[req->n-1];
bundle->height = block->height - 1;
bundle->blocks = mycalloc('B',req->n,sizeof(*bundle->blocks));
bundle->blocks[0] = *block;
prevhash2 = block->prev_block;
for (i=0; i<req->n; i++)
{
height = (bundle->height + 1 + i);
bundle->blocks[i].prev_block = prevhash2;
bundle->blocks[i].hash2 = req->blockhashes[i];
prevhash2 = req->blockhashes[i];
if ( (height % coin->chain->bundlesize) == 0 )
iguana_bundleinit(coin,height,req->blockhashes[i]);
}
printf("initialized bundlei.%d %d\n",bundle->bundlei,bundle->height);
}
portable_mutex_unlock(&bundle->mutex);
} else printf("couldnt find matching bundle for %s\n",bits256_str(block->prev_block));
myfree(req->blockhashes,req->n * sizeof(*req->blockhashes));
myfree(req,sizeof(*req));
} else printf("unexpected missing blockhashes.%p\n",req->blockhashes);
} else printf("unexpected hash2 mismatch with height.%d\n",block->height);
}
else
{
if ( bundle == 0 )
{
printf("cant find bundle.(%s)\n",bits256_str(block->hash2));
return;
}
if ( height > bundle->height && height <= bundle->height+bundle->num )
{
h = height - bundle->height - 1;
portable_mutex_lock(&bundle->mutex);
if ( bundle->numvalid < bundle->num && bundle->txdata[h] == 0 )
{
bundle->blocks[h] = *block;
if ( iguana_recvblockptr(coin,height) == &bundle->txdata[h] && bundle->txdata[h] == 0 )
{
bundle->txdata[h] = txarray, bundle->numtxs[h] = numtx;
coin->blocks.numblocks++;
//if ( (rand() % 100) == 0 )
printf("GOT.%d | received.%d total.%d | %.2f minutes\n",height,coin->blocks.recvblocks,coin->blocks.numblocks,(double)(now - coin->starttime)/60.);
txarray = 0;
if ( ++bundle->numvalid == bundle->num )
{
bundle->recvfinish = now;
bundle->lastduration = (bundle->recvfinish - bundle->recvstart);
dxblend(&coin->R.avetime,bundle->lastduration,.9);
if ( bundle->lastduration < coin->R.avetime )
coin->R.faster++;
else coin->R.slower++;
if ( coin->R.faster > 3*coin->R.slower || coin->R.slower > 3*coin->R.faster )
{
dir = (coin->R.maxrecvbundles - coin->R.prevmaxrecvbundles);
if ( coin->R.slower >= coin->R.faster )
dir = -dir;
if ( dir > 0 )
dir = 1;
else if ( coin->R.maxrecvbundles > 2 )
dir = -1;
else dir = 0;
printf("(%d vs %f) faster.%d slower.%d -> dir.%d apply -> %d\n",bundle->lastduration,coin->R.avetime,coin->R.faster,coin->R.slower,dir,coin->R.maxrecvbundles + dir);
coin->R.prevmaxrecvbundles = coin->R.maxrecvbundles;
coin->R.maxrecvbundles += dir;
coin->R.slower = coin->R.faster = 0;
}
coin->R.finishedbundles++;
printf("submit emit.%d height.%d\n",bundle->bundlei,bundle->height);
queue_enqueue("emitQ",&coin->emitQ,&bundle->DL,0);
}
else
{
if ( coin->R.waitstart[height] > 0 )
{
if ( bundle->firstblocktime == 0 )
bundle->firstblocktime = now;
bundle->durationsum += (now - coin->R.waitstart[height] + 1);
bundle->aveduration = (bundle->durationsum / bundle->numvalid);
}
}
} else printf("recvblockptr error? height.%d %p %p h.%d\n",height,iguana_recvblockptr(coin,height),&bundle->txdata[h],h);
} else if ( (rand() % 1000) == 0 )
printf("interloper! already have txs[%d] for bundlei.%d\n",h,bundle!=0?bundle->height:-1);
portable_mutex_unlock(&bundle->mutex);
} else printf("height.%d outside range of bundlei.%d %d\n",height,bundle!=0?bundle->height:-1,bundle!=0?bundle->height:-1);
}
//iguana_waitclear(coin,block->height);
if ( 1 && (rand() % 1000) == 0 )
printf("%-15s pend.(%d %d) got block.%-6d recvblocks %-8.0f recvtotal %-10.0f\n",addr->ipaddr,addr->pendhdrs,addr->pendblocks,block->height,addr->recvblocks,addr->recvtotal);
}
if ( txarray != 0 )
iguana_freetx(txarray,numtx);
myfree(block,sizeof(*block));
}*/
/*
if ( (bp= iguana_bundleinit(coin,-1,blocks[0].prev_block)) != 0 )
{
if ( n > coin->chain->bundlesize )
printf("warning: %s gotheaders.%d is too many vs. %d\n",coin->symbol,n,coin->chain->bundlesize);
portable_mutex_lock(&bundle->mutex);
if ( bundle->blocks == 0 )
{
bundle->num = n;
bundle->blocks = blocks;
bundle->firsthash2 = blocks[0].hash2;
bundle->lasthash2 = blocks[n-1].hash2;
for (i=0; i<n; i++)
{
blocks[i].height = (bundle->height + i + 1);
iguana_gotdata(coin,addr,blocks[i].height,blocks[i].hash2);
if ( (blocks[i].height % coin->chain->bundlesize) == 0 )
iguana_bundleinit(coin,blocks[i].height,blocks[i].hash2);
}
printf("%s set bundle.%d %s\n",addr->ipaddr,bundle->height,bits256_str(blocks[0].prev_block));
}
portable_mutex_unlock(&bundle->mutex);
} else printf("ERROR iguana_gotheaders got bundle.(%s) n.%d that cant be found?\n",bits256_str(blocks[0].prev_block),n);
}*/
int32_t iguana_updatehdrs(struct iguana_info *coin)
{
int32_t flag = 0;
int32_t i,j,m,height,run,flag = 0; uint32_t now; struct iguana_bundle *bundle;
if ( iguana_needhdrs(coin) == 0 )
return(flag);
now = (uint32_t)time(NULL);
run = -1;
for (i=0; i<coin->R.numbundles; i++)
{
if ( i*coin->chain->bundlesize > coin->longestchain )
break;
bundle = &coin->R.bundles[i];
if ( bundle->blocks != 0 )
{
if ( bundle->recvstart == 0 )
{
if ( (coin->R.startedbundles - coin->R.finishedbundles) < coin->R.maxrecvbundles )
{
iguana_queuebundle(coin,bundle);
bundle->recvstart = now;
coin->R.startedbundles++;
printf("startbundle.%d (%d - %d)\n",bundle->height,coin->R.startedbundles,coin->R.finishedbundles);
flag++;
}
}
else if ( bundle->recvfinish == 0 )
{
for (j=m=0; j<bundle->num; j++)
{
height = bundle->height+j+1;
if ( iguana_recvblock(coin,height) != 0 )
m++;
else if ( coin->R.waitstart[height] > 0 )
{
duration = (now - coin->R.waitstart[height]);
if ( duration > 60 || (duration > 10 && bundle->numvalid > 13 && duration > 3.*bundle->aveduration) )
{
if ( now > bundle->lastdisp+15 )
printf("height.%d in bundle.%d duration.%d vs ave %.3f\n",height,bundle->height,duration,bundle->aveduration);
iguana_waitclear(coin,height);
iguana_waitstart(coin,height,bundle->blocks[j].hash2,1);
}
}
else if ( bundle->firstblocktime > 0 && (now - bundle->firstblocktime) > 60 )
{
if ( now > bundle->lastdisp+15 )
printf("height.%d in bundle.%d ave %.3f\n",height,bundle->height,bundle->aveduration);
iguana_waitclear(coin,height);
iguana_waitstart(coin,height,bundle->blocks[j].hash2,1);
bundle->firstblocktime = now;
}
}
if ( 0 && now > bundle->lastdisp+15 )
{
printf("bundle.%d (%d %d) elapsed.%d (%d - %d) %d | %.2f minutes\n",bundle->bundlei,bundle->height,m,(int32_t)(now - bundle->recvstart),coin->R.startedbundles,coin->R.finishedbundles,coin->R.maxrecvbundles,(double)(now - coin->starttime)/60.);
bundle->lastdisp = now;
}
}
else if ( run == i-1 )
run++;
}
}
//iguana_lookahead(coin,&hash2,0);
return(flag);
}*/
/*struct iguana_block *iguana_block(struct iguana_info *coin,struct iguana_block *space,int32_t height)
{
if ( height <= coin->blocks.hwmheight )
{
if ( iguana_kvread(coin,coin->blocks.db,0,space,(uint32_t *)&height) != 0 )
{
if ( bits256_nonz(space->hash2) != 0 )
return(space);
if ( height < coin->blocks.hwmheight )
{
printf("height.%d null blockhash? prev.%s\n",height,bits256_str(space->prev_block));
getchar();
}
return(0);
} else printf("error doing RWmmap\n");
}
//printf("iguana_block hwmheight.%d vs height.%d\n",coin->blocks.hwmheight,height);
return(0);
}
struct iguana_block *iguana_findblock(struct iguana_info *coin,struct iguana_block *space,bits256 hash2)
{
struct iguana_block *block = 0; uint32_t itemind;
if ( bits256_nonz(hash2) != 0 )
{
block = iguana_kvread(coin,coin->blocks.db,hash2.bytes,space,&itemind);
//printf("iguana_findblock block.%p itemind.%d\n",block,itemind);
if ( block == 0 || itemind != block->height )
{
if ( block != 0 && block->height != itemind )
{
printf("iguana_findblock (%s) error itemind.%d vs %d block.%p\n",bits256_str(hash2),itemind,block!=0?block->height:-1,block);
getchar();
}
return(0);
}
}
return(block);
}*/
struct iguana_bundle *iguana_bundlefindprev(struct iguana_info *coin,int32_t *heightp,bits256 prevhash2)
{
struct iguana_block *block;
*heightp = -1;
if ( (block= iguana_blockfind(coin,prevhash2)) != 0 )
{
*heightp = block->hh.itemind;
if ( block->bundle == 0 )
{
if ( *heightp == 0 )
block->bundle = coin->B[0];
else block->bundle = coin->B[(block->hh.itemind - 1) / coin->chain->bundlesize];
}
return(block->bundle);
}
else return(0);
}
/*int32_t iguana_bundleset(struct iguana_info *coin,int32_t origheight,bits256 hash2)
{
int32_t bundlei,blocki,height = origheight; struct iguana_bundle *bp = 0;
//printf("bundleset.(%d %s)\n",height,bits256_str(hash2));
if ( (height % coin->chain->bundlesize) == 0 && height > 0 )
{
iguana_blockhashset(coin,origheight,hash2,0);
return(0);
}
if ( (bundlei= iguana_bundlei(coin,&blocki,height)) >= 0 && bundlei >= 0 && (bp= coin->B[bundlei]) != 0 )
{
if ( height > bp->height && height < bp->height+bp->num )
{
if ( iguana_blockhashset(coin,origheight,hash2,bp) != 0 )
{
return(0);
}
printf("iguana_bundleset error setting bundle height.%d %s\n",height,bits256_str(hash2));
} else printf("iguana_bundleset illegal height.%d for bundle.%d\n",height,bp->height);
} else printf("iguana_bundleset illegal height.%d bundlei.%d blocki.%d bp.%p\n",height,bundlei,blocki,bp);
return(-1);
}*/
/*int32_t iguana_bundlei(struct iguana_info *coin,int32_t *blockip,int32_t height)
{
int32_t bundlei;
*blockip = -1;
if ( height <= 0 || height > coin->R.numwaitingbits )
return(-1);
height--;
*blockip = (height % coin->chain->bundlesize);
if ( (bundlei= (height / coin->chain->bundlesize)) < IGUANA_MAXBUNDLES )
return(bundlei);
else return(-1);
}
void **iguana_recvblockptr(struct iguana_info *coin,int32_t *blockip,int32_t height)
{
int32_t bundlei; struct iguana_bundle *bp;
if ( (bundlei= iguana_bundlei(coin,blockip,height)) >= 0 )
{
if ( (bp= coin->B[bundlei]) != 0 )
return(&bp->txdata[*blockip]);
}
return(0);
}*/
/*struct iguana_bundle *iguana_bundleinit(struct iguana_info *coin,int32_t height,bits256 hash2)
{
int32_t bundlei,blocki; struct iguana_bundle *bp = 0;
if ( height < 0 || (height % coin->chain->bundlesize) != 0 )
{
printf("bundleinit error: height.%d %s\n",height,bits256_str(hash2));
return(bp);
}
portable_mutex_lock(&coin->bundles_mutex);
if ( (bundlei= iguana_bundlei(coin,&blocki,height+1)) >= 0 )
{
if ( (bp= coin->B[bundlei]) != 0 )
{
if ( memcmp(hash2.bytes,bp->prevhash2.bytes,sizeof(hash2)) != 0 )
{
if ( bits256_nonz(hash2) > 0 )
{
if ( bits256_nonz(bp->prevhash2) > 0 )
{
printf("bundleinit[%d]: %d hash conflict have %s, got %s\n",bp->bundlei,bp->height,bits256_str(bp->prevhash2),bits256_str2(hash2));
//getchar();
portable_mutex_unlock(&coin->bundles_mutex);
return(0);
}
bp->prevhash2 = hash2;
iguana_blockhashset(coin,height,hash2,1);
printf("bundleinit: set starting hash.(%s) for %d\n",bits256_str(hash2),bp->height);
}
}
}
else
{
bp = mycalloc('b',1,sizeof(*bp));
coin->B[bundlei] = bp; // cant change values once set to nonzero
bp->prevhash2 = hash2;
bp->bundlei = bundlei;
bp->hasheaders = coin->chain->hasheaders;
bp->num = coin->chain->bundlesize;
bp->height = (bundlei * coin->chain->bundlesize);
bp->starttime = (uint32_t)time(NULL);
if ( bits256_nonz(hash2) > 0 )
{
iguana_blockhashset(coin,height,hash2,1);
printf("created bundle.%d: %s coin->B[%d] <- %p\n",height,bits256_str(hash2),bundlei,bp);
}
}
}
portable_mutex_unlock(&coin->bundles_mutex);
return(bp);
}*/
int32_t iguana_waitstart(struct iguana_info *coin,int32_t height,bits256 hash2,int32_t priority)
{
if ( height < 0 || iguana_recvblock(coin,height) == 0 )
return(iguana_queueblock(coin,height,hash2,priority));
else if ( height < coin->maxblockbits )
printf("iguana_waitstart ignore height.%d < %d, %p GETBIT.%d\n",height,coin->maxblockbits,iguana_recvblock(coin,height),GETBIT(coin->R.waitingbits,height));
return(0);
}
int32_t iguana_waitclear(struct iguana_info *coin,int32_t height)
{
if ( height < coin->maxblockbits )
{
//printf("%d waitclear.%d parsed.%d\n",coin->R.numwaiting,height,coin->blocks.recvblocks);
if ( coin->R.numwaiting > 0 )
coin->R.numwaiting--;
coin->R.waitstart[height] = 0;
CLEARBIT(coin->R.waitingbits,height);
return(0);
}
return(-1);
}
int32_t iguana_updatewaiting(struct iguana_info *coin,int32_t starti,int32_t max)
{
int32_t i,height,gap,n = 0; uint32_t now;
now = (uint32_t)time(NULL);
height = starti;
iguana_waitclear(coin,height);
iguana_waitstart(coin,height,coin->R.blockhashes[height],1);
for (i=0; i<max; i++,height++)
{
gap = (height - coin->blocks.recvblocks);
if ( gap >= 0 )
gap = sqrt(gap);
if ( gap < 13 )
gap = 13;
if ( height < coin->maxblockbits && iguana_recvblock(coin,height) == 0 && now > (coin->R.waitstart[height] + gap) && memcmp(bits256_zero.bytes,coin->R.blockhashes[height].bytes,sizeof(bits256)) != 0 )
{
//printf("restart height.%d width.%d widthready.%d %s\n",height,coin->width,coin->widthready,bits256_str(coin->R.blockhashes[height]));
iguana_waitclear(coin,height);
iguana_waitstart(coin,height,coin->R.blockhashes[height],0);
} //else printf("%d %d %p %u\n",height,coin->maxblockbits,coin->R.recvblocks[height],coin->R.waitstart[height]);
}
//printf("height.%d max.%d\n",starti,max);
height = starti;
for (i=0; i<max; i++,height++)
if ( iguana_recvblock(coin,height) != 0 )
n++;
return(n);
}
uint32_t iguana_issuereqs(struct iguana_info *coin)
{
int32_t width,w;
coin->width = width = 4*sqrt(coin->longestchain - coin->blocks.recvblocks);
if ( coin->width < 0 )
width = 500;
coin->widthready = 0;
coin->width = 5000;
//printf("width.%d\n",width);
while ( iguana_recvblock(coin,coin->blocks.recvblocks) != 0 )
{
coin->blocks.recvblocks++;
//printf("RECV.%d\n",coin->blocks.recvblocks);
}
while ( width < (coin->longestchain - coin->blocks.recvblocks) )
{
w = iguana_updatewaiting(coin,coin->blocks.recvblocks,width);
//printf("w%d ",w);
if ( width == coin->width )
coin->widthready = w;
//else
break;
width <<= 1;
if ( width >= coin->longestchain-coin->blocks.recvblocks )
width = coin->longestchain-coin->blocks.recvblocks-1;
if ( (rand() % 100) == 0 && width > (coin->width<<2) )
printf("coin->width.%d higher width.%d all there, w.%d\n",coin->width,width,w);
}
return((uint32_t)time(NULL));
}
int32_t iguana_connectsocket(int32_t blockflag,struct iguana_peer *A,struct sockaddr *addr,socklen_t addr_len)
{
int32_t opt,flags; struct timeval timeout; //,val = 65536*2
if ( A->usock >= 0 )
{
printf("iguana_connectsocket: (%s) already has usock.%d\n",A->ipaddr,A->usock);
return(-1);
}
if ( A->ipv6 != 0 )
A->usock = socket(AF_INET6,SOCK_STREAM,IPPROTO_TCP);
else A->usock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if ( A->usock >= 0 )
{
//setsockopt(A->usock,SOL_SOCKET,SO_SNDBUF,&val,sizeof(val));
//setsockopt(A->usock,SOL_SOCKET,SO_RCVBUF,&val,sizeof(val));
timeout.tv_sec = 0;
timeout.tv_usec = 1000;
setsockopt(A->usock,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout));
setsockopt(A->usock,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout));
opt = 1;
setsockopt(A->usock,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(opt));
//retval = setsockopt(A->usock,SOL_SOCKET,SO_NOSIGPIPE,&opt,sizeof(opt));
//printf("nosigpipe retval.%d\n",retval);
if ( blockflag != 0 || ((flags= fcntl(A->usock,F_GETFL,0)) >= 0 && fcntl(A->usock,F_SETFL,flags|O_NONBLOCK) >= 0) )
{
if ( connect(A->usock,addr,addr_len) >= 0 || errno == EINPROGRESS )
return(A->usock);
else fprintf(stderr,"usock %s connect -> errno.%d\n",A->ipaddr,errno);
}// else fprintf(stderr,"usock %s fcntl -> flags.%d errno.%d",ipaddr,flags,errno);
} else fprintf(stderr,"usock %s -> errno.%d\n",A->ipaddr,errno);
return(-errno);
}
int32_t iguana_connect(struct iguana_info *coin,struct iguana_peer *addrs,int32_t maxaddrs,char *ipaddr,uint16_t default_port,int32_t connectflag)
{
struct sockaddr *addr; struct sockaddr_in6 saddr6; struct sockaddr_in saddr4; uint32_t ipbits;
struct addrinfo hints,*res; socklen_t addr_len; struct addrinfo *ai; int32_t retval = -1,status,n = 0;
addrs[n].usock = -1;
memset(&hints,0,sizeof(hints));
memset(&saddr6,0,sizeof(saddr6));
memset(&saddr4,0,sizeof(saddr4));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
//printf("getaddrinfo\n");
if ( getaddrinfo(ipaddr,NULL,&hints,&res))
{
printf("cant get addrinfo for (%s)\n",ipaddr);
return(-1);
}
for (ai=res; ai!=NULL&&n<maxaddrs; ai=ai->ai_next)
{
if ( ai->ai_family == AF_INET6 )
{
struct sockaddr_in6 *saddr = (struct sockaddr_in6 *)ai->ai_addr;
memcpy(&addrs[n].A.ip,&saddr->sin6_addr,16);
memset(&saddr6,0,sizeof(saddr6));
saddr6.sin6_family = AF_INET6;
memcpy(&saddr6.sin6_addr.s6_addr,&addrs[n].A.ip[0],16);
saddr6.sin6_port = htons(default_port);
addrs[n].ipv6 = 1;
addr = (struct sockaddr *)&saddr6;
addr_len = sizeof(saddr6);
}
else if ( ai->ai_family == AF_INET )
{
struct sockaddr_in *saddr = (struct sockaddr_in *)ai->ai_addr;
memset(&addrs[n].A.ip[0],0,10);
memset(&addrs[n].A.ip[10],0xff,2);
memcpy(&addrs[n].A.ip[12],&saddr->sin_addr,4);
memset(&saddr4,0,sizeof(saddr4));
saddr4.sin_family = AF_INET;
memcpy(&saddr4.sin_addr.s_addr,&addrs[n].A.ip[12],4);
saddr4.sin_port = htons(default_port);
addrs[n].ipv6 = 0;
addr = (struct sockaddr *)&saddr4;
addr_len = sizeof(saddr4);
} else return(-1);
addrs[n].A.nTime = (uint32_t)(time(NULL) - (24 * 60 * 60));
addrs[n].A.port = default_port;
strcpy(addrs[n].ipaddr,ipaddr);
addrs[n].A.nServices = 0;
n++;
if ( connectflag != 0 )
{
ipbits = (uint32_t)calc_ipbits(ipaddr);
addrs[n].usock = -1;
addrs[n].ipbits = ipbits;
strcpy(addrs[n].ipaddr,ipaddr);
//printf("call connectsocket\n");
if ( (addrs[n].usock= iguana_connectsocket(connectflag > 1,&addrs[n],addr,addr_len)) < 0 )
{
status = IGUANA_PEER_KILLED;
printf("refused PEER STATUS.%d for %s usock.%d\n",status,ipaddr,retval);
iguana_iAkill(coin,&addrs[n],1);
if ( iguana_rwipbits_status(coin,1,ipbits,&status) == 0 )
printf("error updating status.%d for %s\n",status,ipaddr);
}
else
{
status = IGUANA_PEER_READY;
printf("CONNECTED! PEER STATUS.%d for %s usock.%d\n",status,ipaddr,addrs[n].usock);
iguana_iAconnected(coin,&addrs[n]);
if ( iguana_rwipbits_status(coin,1,ipbits,&status) == 0 )
printf("error updating status.%d for %s\n",status,ipaddr);
else retval = addrs[n].usock;
}
break;
}
}
freeaddrinfo(res);
return(retval);
}
/*if ( (fp= fopen(fname,"r")) != 0 )
{
if ( fgets(line,sizeof(line),fp) > 0 )
{
line[strlen(line)-1] = 0;
if ( atoi(line) > coin->blocks.hashblocks )
{
//printf("skip save since %s has %d\n",fname,atoi(line));
fclose(fp);
return(0);
}
}
fclose(fp);
}*/
/*struct iguana_bundle
{
struct queueitem DL; portable_mutex_t mutex;
char fname[512]; struct iguana_mappedptr M;
void *txdata[_IGUANA_HDRSCOUNT]; int32_t numtxs[_IGUANA_HDRSCOUNT];
struct iguana_counts presnapshot,postsnapshot;
int32_t bundlei,height,num,hasheaders,numvalid,havehashes;
uint32_t starttime,emitstart,emitfinish,lastdisp;
bits256 prevhash2,firsthash2,lasthash2;
//double durationsum,aveduration;
//struct iguana_block *blocks;
};*/
/*struct iguana_recv
{
//uint8_t compressed[IGUANA_MAXPACKETSIZE],decompressed[IGUANA_MAXPACKETSIZE],checkbuf[IGUANA_MAXPACKETSIZE];
long srcdatalen,compressedtotal; //uint64_t histo[0x100];
struct iguana_memspace RSPACE,*oldRSPACE; int32_t numold;
int64_t packetsallocated,packetsfreed; int32_t numwaiting,maprecvdata;
uint8_t *waitingbits; uint32_t numwaitingbits,*waitstart; //struct iguana_pending **recvblocks;
int32_t topheight,pendingtopheight;
uint32_t pendingtopstart,numbundles,lasthdrtime,startedbundles,finishedbundles;
bits256 tophash2;
//int32_t prevmaxrecvbundles,maxrecvbundles,faster,slower; double avetime;
};
struct iguana_pending
{
int32_t next,numtx,datalen,origdatalen; struct iguana_block block; uint32_t allocsize,ipbits; uint8_t data[];
};*/
//struct iguana_recv R;
//struct iguana_bundle *B[IGUANA_MAXBUNDLES];
//struct iguana_blockhashes pendings[1024];
/* int32_t height;
height = iguana_blockheight(coin,blockhashes[0]);
if ( n > 2 && iguana_needhdrs(coin) > 0 )
{
//printf("got blockhashes[%d] %s height.%d\n",n,bits256_str(blockhashes[0]),height);
if ( height >= 0 )
{
for (j=0; j<n && j<coin->chain->bundlesize && height+j<coin->longestchain; j++)
{
iguana_bundleset(coin,height+j,blockhashes[j]);
iguana_gotdata(coin,0,height+j,blockhashes[j],j,n);
}
}
else
{
iguana_queueblock(coin,-1,blockhashes[0],1);
for (i=0; i<coin->numpendings; i++)
if ( memcmp(coin->pendings[i].blockhashes[0].bytes,blockhashes[0].bytes,sizeof(bits256)) == 0 )
break;
if ( i == coin->numpendings )
{
if ( coin->numpendings < sizeof(coin->pendings)/sizeof(*coin->pendings) )
{
coin->pendings[coin->numpendings].blockhashes = blockhashes;
coin->pendings[coin->numpendings].n = n;
coin->pendings[coin->numpendings].starttime = (uint32_t)time(NULL);
coin->numpendings++;
printf("ADD to numpendings.%d priority.(%s) n.%d\n",coin->numpendings,bits256_str(blockhashes[0]),n);
blockhashes = 0;
} else printf("updatebundles: overflowed pendings\n");
}
}
}*/
/* if ( iguana_bundlefindprev(coin,&height,blocks[0].prev_block) != 0 && height >= 0 )
{
//printf(">>>>>> found %s height.%d n.%d\n",bits256_str(blocks[0].prev_block),height,n);
height++;
for (i=0; i<n && i<coin->chain->bundlesize && height<coin->longestchain; i++,height++)
{
//printf("i.%d height.%d\n",i,height);
iguana_bundleset(coin,height,blocks[i].hash2);
iguana_gotdata(coin,req->addr,height,blocks[i].hash2,i,n);
if ( height >= coin->blocks.hwmheight )
{
if ( height == coin->blocks.hwmheight )
(*newhwmp)++;
if ( (block= iguana_block(coin,height)) != 0 )
iguana_mergeblock(block,&blocks[i]);
else printf("unexpected null block at height.%d\n",height), getchar();
}
else
{
// verify it doesnt trigger reorg (and is recent enough!)
}
}
} else printf("unexpected bundlefind error %s height.%d\n",bits256_str(blocks[0].prev_block),height), getchar();
*/
/* int32_t height;
//printf("%s got block.(%s) height.%d\n",req->addr!=0?req->addr->ipaddr:"local",bits256_str(block->hash2),height);
if ( (height= iguana_bundleheight(coin,block)) > 0 )
{
if ( (ptrp= iguana_blockptrptr(coin,&blocki,height)) != 0 )
{
if ( (*ptrp) == 0 )
{
//printf("height.%d tx.%p blocki.%d txarray.%p[%d] (%p[%d] %p[%d])\n",height,&txarray[0],blocki,txarray,numtx,txarray[0].vouts,txarray[0].tx_out,txarray[0].vins,txarray[0].tx_in);
(*ptrp) = (void *)txarray;
bp->numtxs[blocki] = numtx;
if ( bp->emitstart == 0 && ++bp->numvalid >= bp->num )
{
bp->emitstart = (uint32_t)time(NULL);
iguana_emittxdata(coin,bp);
//printf("queue txarray.%p[%d]\n",txarray,numtx);
//queue_enqueue("emitQ",&coin->emitQ,&bp->DL,0);
}
//txarray = 0;
}
}
else printf("cant get ptrp.%d\n",height), getchar();
iguana_gotdata(coin,req->addr,height,block->hash2,0,0);
if ( bp != 0 && iguana_bundleready(coin,height-1) <= 0 )
{
printf("check for pendings.%d height.%d\n",coin->numpendings,height);
if ( height == coin->blocks.hwmheight )
(*newhwmp)++;
for (i=0; i<coin->numpendings; i++)
if ( memcmp(coin->pendings[i].blockhashes[0].bytes,block->hash2.bytes,sizeof(block->hash2)) == 0 )
{
blockhashes = coin->pendings[i].blockhashes;
n = coin->pendings[i].n;
printf("pending[%d].%d bundlesets[%d] %d %s\n",i,coin->numpendings,n,height,bits256_str(blockhashes[0]));
for (j=0; j<n && j<coin->chain->bundlesize && height+j<coin->longestchain; j++)
{
iguana_bundleset(coin,height+j,blockhashes[j]);
iguana_gotdata(coin,0,height+j,blockhashes[j],j,n);
}
myfree(blockhashes,n * sizeof(*blockhashes));
coin->pendings[i] = coin->pendings[--coin->numpendings];
break;
}
// queue tx for processing
}
else
{
// probably new block
//printf("couldnt find.(%s)\n",bits256_str(block->hash2));
}
}*/
//if ( height >= 0 )
// coin->blocks.ptrs[height] = block;
//printf("found.%s -> %s %d %p inputht.%d\n",bits256_str(hash2),bits256_str(block->hash2),block->hh.itemind,block,height);
if ( height < 0 || block->hh.itemind == height )
{
if ( (int32_t)block->hh.itemind < 0 )
{
//printf("found.%s -> %d %p set height.%d matches.%d\n",bits256_str(hash2),block->hh.itemind,block,height,block->matches);
if ( height >= 0 && block->matches == 0 )
block->hh.itemind = height, block->matches = 1;
else block = 0;
}
if ( block != 0 )
{
if ( block->matches < 100 )
block->matches++;
//_iguana_blocklink(coin,block);
}
}
else if ( block->matches == 0 && block->hh.itemind == (uint32_t)-1 )
{
if ( height >= 0 )
{
if ( (rand() % 10000) == 0 )
printf("set %s.itemind <- %d\n",bits256_str(hash2),height);
block->hh.itemind = height;
block->matches = 1;
}
else
{
printf("matches.%d itemind.%d when height.%d\n",block->matches,block->hh.itemind,height);
block = 0;
}
}
else
{
/*if ( block->matches < 100 )
{
block->matches >>= 1;
if ( block->matches == 0 )
{
//printf("collision with (%s) itemind.%d vs %d | matches.%d\n",bits256_str(hash2),block->hh.itemind,height,block->matches);
block->hh.itemind = -1;
for (i=0; i<1; i++)
iguana_queueblock(coin,-1,block->hash2,1);
block = 0;
//coin->blocks.recvblocks = 0;
}
} else block = 0;*/
}
/*int32_t iguana_blockheight(struct iguana_info *coin,struct iguana_block *block)
{
int32_t height;
if ( (height= iguana_itemheight(coin,block->hash2)) < 0 )
{
if ( (height= iguana_itemheight(coin,block->prev_block)) < 0 )
{
iguana_blockhashset(coin,-1,block->hash2,1);
iguana_blockhashset(coin,-1,block->prev_block,1);
}
else
{
height++;
iguana_blockhashset(coin,height,block->hash2,1);
}
} else iguana_blockhashset(coin,height,block->hash2,1); // increments matches
return(height);
}*/
if ( (height= iguana_itemheight(coin,blockhashes[0])) >= 0 )
{
if ( iguana_needhdrs(coin) > 0 && iguana_havetxdata(coin,h) == 0 )
iguana_queueblock(coin,height,blockhashes[0],1);
}
else if ( iguana_needhdrs(coin) > 0 && iguana_havetxdata(coin,h) == 0 )
iguana_queueblock(coin,-1,blockhashes[0],1);
//printf("check.%s height.%d\n",bits256_str(blockhashes[0]),height);
for (i=0; i<n; i++)
{
if ( height >= 0 )
h = height++;
permblock = iguana_blockhashset(coin,h,blockhashes[i],1);
if ( h >= 0 && permblock != 0 )
{
if ( iguana_blockptr(coin,h) == 0 )
{
coin->blocks.ptrs[h] = permblock;
{
int32_t j,m;
for (j=m=0; j<coin->longestchain; j++)
if ( iguana_blockptr(coin,j) != 0 )
m++;
printf("set (%s) <- %d %p m.%d\n",bits256_str(blockhashes[i]),h,permblock,m);
}
}
if ( permblock->hh.itemind != h )
permblock->hh.itemind = h;
}
if ( i == coin->chain->bundlesize-1 )
{
init_hexbytes_noT(hashstr,blockhashes[i].bytes,sizeof(blockhashes[i]));
queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1);
}
//else //if ( h >= 0 ) printf("unexpected missing permblock for h.%d\n",h);
// iguana_queueblock(coin,-1,blockhashes[i],0);
}
for (i=m=run=0; i<num&&i<_IGUANA_HDRSCOUNT; i++)
{
if ( (height= iguana_heightwt(coin,&wt,blockhashes[i])) >= 0 )
{
if ( run == i && (i == 0 || height == height0+i) )
run++;
if ( (block= iguana_blockfind(coin,blockhashes[i])) != 0 && block == blocks[i] && block->mainchain == 0 )
{
if ( block->hh.itemind != height && wt > block->matches )
{
printf("%p[%d] <- %d matches.%d wt.%d vs matches.%d\n",block,block->hh.itemind,height,block->matches,wt,block->matches);
if ( block->matches < 100 )
{
block->matches = 1;
block->hh.itemind = height;
}
else printf("height conflict for %s\n",bits256_str(blockhashes[i]));
}
} else blocks[i] = 0;
if ( i == 0 )
height0 = height;
height -= i;
if ( m > 0 )
{
for (j=0; j<m; j++)
{
if ( heightwts[j][0] == height )
{
heightwts[j][1] += wt;
//printf("matches j.%d m.%d wt.%d -> %d\n",j,m,wt,heightwts[j][1]);
break;
}
}
} else j = 0;
if ( j == m )
{
heightwts[m][0] = height;
heightwts[m][1] = wt;
m++;
}
}
printf("i.%d j.%d m.%d height.%d wt.%d %s\n",i,j,m,height,wt,bits256_str(blockhashes[0]));
}
nlinks = plinks = 0;
if ( m > 0 )
{
if ( m == 1 && height0 >= 0 )
{
wt = (heightwts[0][1] / num) + 2;
for (i=0; i<num; i++)
if ( blocks[i] == 0 )
break;
if ( i == num )
{
//printf("height0.%d\n",height0);
if ( (prev= iguana_blockptr(coin,height0 - 1)) != 0 )
{
if ( prev->hh.next == 0 || prev->matches < wt )
prev->hh.next = blocks[0];
}
for (i=plinks=nlinks=0; i<num; i++)
{
next = (i < num) ? blocks[i+1] : iguana_blockptr(coin,height0 + num);
if ( (block= blocks[i]) != 0 )
{
if ( (int32_t)block->hh.itemind < 0 || block->matches < wt )
{
block->hh.itemind = height0 + i;
block->matches = (wt < 100) ? wt : 100;
SETBIT(coin->havehash,height0 + i);
//iguana_blockhashset(coin,height0 + i,blockhashes[i],(wt < 100) ? wt : 100);
}
if ( (block->hh.prev == 0 || block->matches < wt) && block->hh.prev != prev )
block->hh.prev = prev, plinks++;
if ( (block->hh.next == 0 || block->matches < wt) && block->hh.next != next )
block->hh.next = next, nlinks++;
if ( block->matches < 100 )
block->matches++;
} else printf("recvblockhashes: blocks[%d] null\n",i);
prev = block;
}
if ( next != 0 && (next->hh.prev == 0 || next->matches < wt) )
next->hh.prev = prev;
} else printf("recvblockhashes: i.%d != num.%d\n",i,num);
}
if ( height0 >= 0 && 0 )
{
for (i=0; i<m; i++)
printf("(h%d %d) ",heightwts[i][0],heightwts[i][1]);
printf("%s m.%d run.%d wt.%d height0.%d plinks.%d nlinks.%d\n",bits256_str(blockhashes[0]),m,run,wt,height0,plinks,nlinks);
}
} else printf("recvblockhashes: m.%d height0.%d %s[%d]\n",m,height0,bits256_str(blockhashes[0]),num);
prev = 0;
for (i=m=0; i<num; i++)
{
if ( (block= iguana_blockhashset(coin,-1,blockhashes[i],1)) != 0 )
{
next = (i < num) ? iguana_blockhashset(coin,-1,blockhashes[i+1],1) : 0;
if ( (height= iguana_heightwt(coin,&wt,prev,block,next)) >= 0 )
{
if ( i == 0 )
height0 = height, block0 = block;
m++;
//printf("height %d, wt %d itemind.%d matches.%d\n",height,wt,block->hh.itemind,block->matches);
if ( (int32_t)block->hh.itemind < 0 || block->matches*3 < wt )
{
SETBIT(coin->havehash,height);
block->hh.itemind = height;
block->matches = (wt/3) + 1;
}
if ( prev != 0 && ((int32_t)prev->hh.itemind < 0 || prev->matches*3 < wt) )
{
SETBIT(coin->havehash,height - 1);
prev->hh.itemind = height - 1;
prev->matches = (wt/3) + 1;
}
if ( next != 0 && ((int32_t)next->hh.itemind < 0 || next->matches*3 < wt) )
{
SETBIT(coin->havehash,height + 1);
next->hh.itemind = height + 1;
next->matches = (wt/3) + 1;
}
}
}
prev = block;
}
if ( m >= coin->chain->bundlesize && height0 >= 0 && block != 0 )
{
printf("gothdr.%d oldgothdr.%d %p %d <- %p\n",height0,block->gothdrs,coin->blocks.ptrs[height0],coin->blocks.ptrs[height0]!=0?coin->blocks.ptrs[height0]->hh.itemind:0,block);
coin->blocks.ptrs[height0] = block;
block->gothdrs = 1;
}
int32_t i,m,height,wt,height0 = -1; struct iguana_block *block,*next,*prev,*block0 = 0;
int32_t iguana_blockmetric(struct iguana_info *coin,int32_t *wtp,struct iguana_block *block)
{
int32_t height = -1; int64_t wt;
if ( block->mainchain != 0 && block->height >= 0 )
{
height = block->height;
wt = ((int64_t)coin->blocks.hwmheight - block->height) * 10000;
if ( wt > (1 << 28)/_IGUANA_HDRSCOUNT )
wt = (1 << 28) / _IGUANA_HDRSCOUNT;
(*wtp) += (int32_t)wt;
}
else if ( block->height >= 0 )
{
height = block->height;
(*wtp) += 10;
}
else if ( (int32_t)block->hh.itemind >= 0 )
{
height = block->hh.itemind;
(*wtp) += block->matches;
}
return(height);
}
int32_t iguana_heightwt(struct iguana_info *coin,int32_t *wtp,struct iguana_block *prev,struct iguana_block *block,struct iguana_block *next)
{
int32_t heightwts[3][2],height,i,n = 0;
*wtp = 0;
height = -1;
memset(heightwts,0,sizeof(heightwts));
if ( block != 0 )
{
if ( (heightwts[1][0]= iguana_blockmetric(coin,&heightwts[1][1],block)) >= 0 )
n++;
//printf("%s itemind.%d matches.%d ht.%d metric.%d n.%d\n",bits256_str(hash2),block->hh.itemind,block->matches,heightwts[1][0],heightwts[1][1],n);
if ( prev != 0 )//|| (prev= block->hh.prev) != 0 )
{
if ( (heightwts[0][0]= iguana_blockmetric(coin,&heightwts[0][1],prev)) >= 0 )
{
//printf("heightwts(%d + 1) vs %d\n",heightwts[0][0],heightwts[1][0]);
if ( heightwts[0][0]+1 == heightwts[1][0] )
n++;
else n--, heightwts[0][0] = -1;
}
//printf("%s itemind.%d matches.%d ht.%d metric.%d n.%d\n",bits256_str(prev->hash2),prev->hh.itemind,prev->matches,heightwts[0][0],heightwts[0][1],n);
}
if ( next != 0 )//(next= block->hh.prev) != 0 && next != block )
{
if ( (heightwts[2][0]= iguana_blockmetric(coin,&heightwts[2][1],next)) >= 0 )
{
if ( heightwts[2][0]-1 == heightwts[1][0] )
n++;
else n--, heightwts[2][0] = -1;
}
//printf("%s itemind.%d matches.%d ht.%d metric.%d n.%d\n",bits256_str(next->hash2),next->hh.itemind,next->matches,heightwts[2][0],heightwts[2][1],n);
}
if ( n > 0 )
{
for (i=0; i<3; i++)
if ( heightwts[i][0] >= 0 )
(*wtp) += heightwts[i][1];
(*wtp) *= n;
height = heightwts[1][0];
}
} //else printf("cant find.(%s)\n",bits256_str(hash2));
return(height);
}
/*n = 0;
if ( 0 && n == 0 && time(NULL) > coin->hdrstime+30 )
{
height = (coin->blocks.hashblocks / coin->chain->bundlesize) * coin->chain->bundlesize;
while ( height < (coin->longestchain - coin->chain->bundlesize - 1) )
{
if ( (hdrs= iguana_addhdr(coin,block->hash2,bits256_zero)) != 0 && hdrs->block.gothdrs == 0 )
{
flag++;
//printf("REQ HDR.(%s) %d\n",bits256_str(block->hash2),height);
printf("%d ",height);
n++;
init_hexbytes_noT(hashstr,hdrs->bundlehash2.bytes,sizeof(bits256));
queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1);
}
height += coin->chain->bundlesize;
}
coin->hdrstime = (uint32_t)time(NULL);
}
if ( n > 0 )
printf("REQ EXTRA HDRS\n");*/
if ( offset == 0 )
printf("unhandled case offset.0\n");
else
{
struct iguana_block *block;
if ( bits256_nonz(hdrs->bundlehash2) == 0 )
{
if ( (block= iguana_blockfind(coin,blockhashes[0])) != 0 )
hdrs->bundlehash2 = block->prev_block;
}
}
struct iguana_block *iguana_updatehdrs(struct iguana_info *coin,int32_t *newhwmp,struct iguana_block *block,bits256 prevhash2,bits256 hash2)
{
struct iguana_bundlereq *hdrs; int32_t i,offset,height;
if ( (hdrs= iguana_addhdr(coin,&offset,0,prevhash2,hash2)) != 0 && hdrs->bundleheight >= 0 )
{
iguana_blockset(coin,hdrs->bundleheight,hdrs->bundlehash2);
height = (hdrs->bundleheight + offset);
if ( block != 0 )
{
block->hh.itemind = height;
hdrs->block = *block;
prevhash2 = block->prev_block, hash2 = block->hash2;
if ( height > 0 )
iguana_blockset(coin,height - 1,prevhash2);
if ( height <= coin->blocks.hwmheight )
{
if ( height < coin->blocks.hwmheight || coin->blocks.dirty == 0 )
coin->blocks.dirty = height;
(*newhwmp)++;
}
}
if ( hdrs->hashes != 0 )
{
for (i=0; i<hdrs->n; i++)
if ( memcmp(block->hash2.bytes,hdrs->hashes[i].bytes,sizeof(bits256)) == 0 )
break;
printf("got block.(%s) height.%d i.%d\n",bits256_str(block->hash2),height,i);
for (; i<hdrs->n; i++,height++)
iguana_blockset(coin,height,hdrs->hashes[i]);
} else printf("no blockhashes.%d\n",hdrs->bundleheight);
} else printf("cant find hdrs.%s %s %d\n",bits256_str(prevhash2),bits256_str2(hash2),hdrs==0?-1:hdrs->bundleheight), getchar();
return(iguana_blockfind(coin,hash2));
}
struct iguana_block *iguana_blockset(struct iguana_info *coin,int32_t height,bits256 hash2)
{
struct iguana_block *block; int32_t offset,h,flag; struct iguana_bundlereq *hdrs;
//printf("blockset.%d %s\n",height,bits256_str(hash2));
if ( height < 0 )
getchar();
iguana_blockhashset(coin,height,hash2,100);
if ( (block= iguana_blockfind(coin,hash2)) != 0 )
{
SETBIT(coin->havehash,height);
block->hh.itemind = height;
coin->blocks.ptrs[height] = block;
//printf("SETBIT.%d %s %p\n",hdrs->bundleheight,bits256_str(hdrs->bundlehash2),permblock);
}
if ( (height % coin->chain->bundlesize) == 0 )
{
if ( 0 && (hdrs= iguana_addhdr(coin,&offset,1,hash2,bits256_zero)) != 0 )
{
if ( hdrs->bundleheight != height && hdrs->bundleheight >= 0 )
{
printf("bundleheight.%d -> EXTENDED HDRS.%d %s\n",hdrs->bundleheight,height,bits256_str(hash2));
hdrs->bundleheight = height;
}
}
}
if ( height >= 0 && bits256_nonz(hash2) > 0 )
{
if ( coin->chain->hasheaders == 0 && (height % coin->chain->bundlesize) == 1 && iguana_havetxdata(coin,height) == 0 )
iguana_queueblock(coin,height,hash2,1);
}
return(block);
}
//tmp = iguana_updatehdrs(coin,newhwmp,block,block->prev_block,block->hash2);
if ( (prev= iguana_blockfind(coin,block->prev_block)) != 0 && (int32_t)prev->hh.itemind >= 0 )
{
//printf("recv blockset.%s %d\n",bits256_str(block->hash2),prev->hh.itemind+1);
permblock = iguana_blockset(coin,prev->hh.itemind+1,block->hash2);
//permblock = iguana_blockhashset(coin,prev->hh.itemind+1,block->hash2,1);
}
else if ( (permblock= iguana_blockfind(coin,block->hash2)) == 0 )
printf("cant find block prev.%s\n",bits256_str(block->prev_block));
if ( tmp != 0 && permblock == 0 )
permblock = tmp;
/*struct iguana_block *block; int32_t flag = 0;
while ( coin->blocks.issuedblocks < coin->blocks.hashblocks && coin->blocks.issuedblocks < coin->blocks.recvblocks+coin->chain->bundlesize*IGUANA_INITIALBUNDLES )
{
if ( (block= iguana_blockptr(coin,coin->blocks.issuedblocks)) != 0 && bits256_nonz(block->hash2) != 0 )
iguana_queueblock(coin,coin->blocks.issuedblocks,block->hash2,0);
coin->blocks.issuedblocks++;
flag++;
}
return(flag);*/
/*int32_t iguana_reqblocks(struct iguana_info *coin)
{
int32_t n,height,flag = 0; struct iguana_block *block;
if ( queue_size(&coin->priorityQ) == 0 )
{
coin->pcount++;
if ( coin->pcount > 1 && (block= iguana_blockptr(coin,coin->blocks.recvblocks)) != 0 && coin->blocks.recvblocks < coin->blocks.issuedblocks && bits256_nonz(block->hash2) > 0 )
flag += (iguana_queueblock(coin,coin->blocks.recvblocks,block->hash2,1) > 0);
} else coin->pcount = 0;
if ( queue_size(&coin->blocksQ) == 0 )
{
coin->bcount++;
n = 0;
if ( coin->bcount > 100 && time(NULL) > coin->recvtime+3 )
{
for (height=coin->blocks.recvblocks+1; height<coin->blocks.issuedblocks&&n<coin->chain->bundlesize; height++)
{
if ( (block= iguana_blockptr(coin,coin->blocks.recvblocks)) != 0 && bits256_nonz(block->hash2) > 0 )
{
//if ( (height % 100) == 0 )
printf("RETRY BLOCK.%d\n",height);
flag += (iguana_queueblock(coin,height,block->hash2,0) > 0);
n++;
}
}
//coin->recvtime = (uint32_t)time(NULL);
}
} else coin->bcount = 0;
return(flag);
}
{
bundlei = (height / coin->chain->bundlesize);
if ( GETBIT(coin->emitbits,bundlei) == 0 && iguana_bundleready(coin,height) > 0 )
{
req->bundleheight = bundlei * coin->chain->bundlesize;
SETBIT(coin->emitbits,bundlei);
req->type = 'E';
printf("Q emit.%d\n",req->bundleheight);
queue_enqueue("emitQ",&coin->emitQ,&req->DL,0);
}
}*/
hash2 = iguana_bundleihash2(coin,bp,bundlei);
if ( memcmp(hash2.bytes,block->hash2.bytes,sizeof(hash2)) == 0 )
{
*hdrsp = bp;
*bundleip = bundlei;
if ( bundlei == 0 )
{
if ( (prevbp= iguana_bundlesearch(coin,&prevbundlei,block->bundlehash2,block->prev_block,IGUANA_SEARCHNEXT)) != 0 )
{
if ( prevbundlei == prevbp->n+1 )
{
bp->prevbundlehash2 = prevbp->bundlehash2;
prevbp->nextbundlehash2 = block->hash2;
//printf("prev BUNDLES LINKED! (%d <-> %d) (%s <-> %s)\n",prevbp->bundleheight,bp->bundleheight,bits256_str(prevbp->bundlehash2),bits256_str2(bp->bundlehash2));
if ( prevbp->bundleheight != bp->bundleheight-coin->chain->bundlesize )
printf("WARNING gap in bundleheight %d != %d bundlesize\n",prevbp->bundleheight,bp->bundleheight-coin->chain->bundlesize);
} else printf("prevbundlei.%d != prevhdrs->n %d\n",prevbundlei,prevbp->n+1);
}
}
else if ( bundlei == bp->n )
{
if ( (nextbp= iguana_bundlesearch(coin,&nextbundlei,block->bundlehash2,block->hash2,IGUANA_SEARCHPREV)) != 0 )
{
if ( nextbundlei == 0 )
{
bp->nextbundlehash2 = nextbp->bundlehash2;
nextbp->prevbundlehash2 = block->hash2;
//printf("next BUNDLES LINKED! (%d <-> %d) (%s <-> %s)\n",nextbp->bundleheight,bp->bundleheight,bits256_str(nextbp->bundlehash2),bits256_str2(bp->bundlehash2));
if ( nextbp->bundleheight != bp->bundleheight+coin->chain->bundlesize )
printf("WARNING gap in bundleheight != bundlesize\n");
} else printf("nextbundlei.%d != nextbp->n %d\n",nextbundlei,nextbp->n);
}
}
} else printf("hdrs.%d [%d] unexpected hash2 mismatch for %s != %s\n",bp->bundleheight,bundlei,bits256_str(block->hash2),bits256_str2(hash2));
/*int32_t iguana_havehash(struct iguana_info *coin,int32_t height)
{
return(GETBIT(coin->havehash,height) != 0);
}*/
if ( (bp= iguana_bundlefind(coin,bundleip,block->hash2)) == 0 )
{
if ( (prevbp= iguana_bundlefind(coin,&prevbundlei,block->prev_block)) == 0 )
{
for (j=0; j<coin->bundlescount; j++)
{
if ( (bp= coin->bundles[j]) != 0 )
{
if ( bp->blockhashes != 0 && bp->n > 0 && (bp= iguana_bundlescan(coin,bundleip,bp,block->hash2,IGUANA_SEARCHBUNDLE)) != 0 )
{
return(bp);
}
}
}
return(0);
}
else if ( prevbundlei == prevbp->n )
{
printf("prev AUTOCREATE.%s\n",bits256_str(block->hash2));
iguana_bundlecreate(coin,block->hash2,bits256_zero);
}
}
|| (bp= iguana_bundlefind(coin,bundleip,hash2)) != 0 )
{
if ( (bp= iguana_bundlescan(coin,bundleip,bp,hash2,searchmask)) != 0 )
return(bp);
}
if ( (bp= iguana_bundlefind(coin,bundleip,hash2)) != 0 )
return(bp);
if ( (block= iguana_blockfind(coin,hash2)) == 0 )
iguana_blockhashset(coin,-1,hash2,1);
if ( (block= iguana_blockfind(coin,hash2)) != 0 )
{
if ( bits256_nonz(block->bundlehash2) > 0 )
{
if ( (bp= iguana_bundlefind(coin,&tmp,block->bundlehash2)) != 0 )
return(iguana_bundlescan(coin,bundleip,bp,hash2,searchmask));
}
}
for (i=0; i<n; i++)
{
if ( (block= iguana_recvblockhdr(coin,&bp,&bundlei,&blocks[i],newhwmp)) != 0 && bp != 0 )
{
iguana_bundleblockadd(coin,bp,bundlei,blocks[i].hash2);
} else printf("got hdrs[%d] no block.%p\n",i,block);
}
printf("recv'd %d hdrs\n",n);
if ( n == coin->chain->bundlesize+1 && iguana_bundlefind(coin,&bundlei,blocks[n - 1].hash2,0) == 0 )
{
printf("AUTO EXTEND3.%s[%d]\n",bits256_str(blocks[n - 1].hash2),n);
iguana_bundlecreate(coin,blocks[n - 1].hash2,bits256_zero);
}
//struct iguana_blockhashes { bits256 *blockhashes; int32_t n; uint32_t starttime; };
void iguana_freetx(struct iguana_msgtx *tx,int32_t n)
{
int32_t i,j; struct iguana_msgtx *origtx = tx;
return;
for (j=0; j<n; j++,tx++)
{
//Tx_freed++, Tx_freesize += tx->allocsize;
if ( tx->vins != 0 )
{
for (i=0; i<tx->tx_in; i++)
if ( tx->vins[i].script != 0 )
myfree(tx->vins[i].script,tx->vins[i].scriptlen);
myfree(tx->vins,tx->tx_in * sizeof(*tx->vins));
}
if ( tx->vouts != 0 )
{
for (i=0; i<tx->tx_out; i++)
if ( tx->vouts[i].pk_script != 0 )
myfree(tx->vouts[i].pk_script,tx->vouts[i].pk_scriptlen);
myfree(tx->vouts,tx->tx_out * sizeof(*tx->vouts));
}
}
myfree(origtx,sizeof(*origtx) * n);
}
/*
struct iguana_rawtx { bits256 txid; uint16_t numvouts,numvins; uint8_t rmd160[20]; };
int32_t iguana_emittx(struct iguana_info *coin,FILE *fp,struct iguana_block *block,struct iguana_msgtx *tx,int32_t txi,uint32_t *numvoutsp,uint32_t *numvinsp,int64_t *outputp)
{
int32_t blocknum,i; int64_t reward; uint16_t s; struct iguana_rawtx rawtx; uint8_t rmd160[20],buf[64];
struct iguana_msgvin *vin;
blocknum = block->hh.itemind;
memset(&rawtx,0,sizeof(rawtx));
rawtx.txid = tx->txid;
rawtx.numvouts = tx->tx_out, rawtx.numvins = tx->tx_in;
if ( (blocknum == 91842 || blocknum == 91880) && txi == 0 && strcmp(coin->name,"bitcoin") == 0 )
rawtx.txid.ulongs[0] ^= blocknum;
//printf("%d: tx.%p %p[numvouts.%d] %p[numvins.%d]\n",block->hh.itemind,tx,tx->vouts,tx->tx_out,tx->vins,tx->tx_in);
if ( fwrite(&rawtx,1,sizeof(rawtx),fp) == sizeof(rawtx) )
{
for (i=0; i<rawtx.numvouts; i++)
{
iguana_calcrmd160(coin,rmd160,tx->vouts[i].pk_script,tx->vouts[i].pk_scriptlen,rawtx.txid);
memcpy(buf,&tx->vouts[i].value,sizeof(tx->vouts[i].value));
memcpy(&buf[sizeof(tx->vouts[i].value)],rmd160,sizeof(rmd160));
if ( fwrite(buf,1,sizeof(rmd160)+sizeof(tx->vouts[i].value),fp) == sizeof(rmd160)+sizeof(tx->vouts[i].value) )
{
(*numvoutsp)++;
(*outputp) += tx->vouts[i].value;
} else printf("error writing txi.%d vout.%d\n",txi,i);
}
for (i=0; i<rawtx.numvins; i++)
{
vin = &tx->vins[i];
if ( bits256_nonz(vin->prev_hash) == 0 )
{
if ( i == 0 && (int32_t)vin->prev_vout < 0 )
{
reward = iguana_miningreward(coin,blocknum);
//printf("reward %.8f\n",dstr(reward));
(*outputp) += reward;
} else printf("unexpected prevout.%d\n",vin->prev_vout), getchar();
continue;
}
memcpy(buf,vin->prev_hash.bytes,sizeof(vin->prev_hash));
s = vin->prev_vout;
memcpy(&buf[sizeof(vin->prev_hash)],&s,sizeof(s));
//printf("do spend.%s\n",bits256_str(vin->prev_hash));
if ( fwrite(buf,1,sizeof(bits256)+sizeof(s),fp) == sizeof(bits256)+sizeof(s) )
(*numvinsp)++;
else printf("error writing txi.%d vin.%d\n",txi,i);
}
return(0);
}
else printf("error writing txi.%d blocknum.%d\n",txi,blocknum);
return(-1);
}
void iguana_emittxarray(struct iguana_info *coin,FILE *fp,struct iguana_block *block,struct iguana_msgtx *txarray,int32_t numtx)
{
uint32_t i,numvouts,numvins; int64_t credits; long fpos,endpos;
if ( fp != 0 && block != 0 )
{
//printf("%d/%d: txarray.%p, numtx.%d bp.%p\n",block->hh.itemind,block->hh.itemind,txarray,numtx,bp);
fpos = ftell(fp);
credits = numvouts = numvins = 0;
for (i=0; i<numtx; i++)
iguana_emittx(coin,fp,block,&txarray[i],i,&numvouts,&numvins,&credits);
endpos = ftell(fp);
fseek(fp,fpos,SEEK_SET);
block->L.supply = credits;
block->txn_count = numtx;
block->numvouts = numvouts, block->numvins = numvins;
block->L.numtxids = numtx, block->L.numunspents = numvouts, block->L.numspends = numvins;
if ( fwrite(block,1,sizeof(*block),fp) != sizeof(*block) )
printf("iguana_emittxarray: error writing block.%d\n",block->height);
fseek(fp,endpos,SEEK_SET);
}
}
int32_t iguana_maptxdata(struct iguana_info *coin,struct iguana_mappedptr *M,struct iguana_bundle *bp,char *fname)
{
void *fileptr = 0; int32_t i; uint32_t *offsets; struct iguana_block *block;
if ( (fileptr= iguana_mappedptr(0,M,0,0,fname)) != 0 )
{
offsets = fileptr;
for (i=0; i<bp->n; i++)
{
if ( (block= bp->blocks[i]) != 0 )
{
if ( block->txdata != 0 )
{
if ( block->mapped == 0 )
{
printf("[%d].%d free txdata.%d %p\n",bp->hdrsi,i,((struct iguana_bundlereq *)block->txdata)->allocsize,block->txdata);
myfree(block->txdata,((struct iguana_bundlereq *)block->txdata)->allocsize);
block->txdata = 0;
block->mapped = 0;
}
}
if ( i < coin->chain->bundlesize )
{
block->txdata = (void *)((long)fileptr + offsets[i]);
block->mapped = 1;
}
}
else if ( i < coin->chain->bundlesize )
printf("iguana_maptxdata cant find block[%d]\n",i);
}
return(i < coin->chain->bundlesize ? i : coin->chain->bundlesize);
}
printf("error mapping (%s)\n",fname);
return(-1);
}
void iguana_emittxdata(struct iguana_info *coin,struct iguana_bundle *emitbp)
{
FILE *fp; char fname[512];uint32_t offsets[_IGUANA_HDRSCOUNT+1];
//uint8_t extra[256]; struct iguana_msgtx *txarray,*tx;
struct iguana_bundlereq *req; struct iguana_mappedptr M;
int32_t i,bundleheight,height,numtx,n; long len; struct iguana_block *block;
return;
if ( emitbp == 0 )
return;
sprintf(fname,"tmp/%s/txdata.%d",coin->symbol,emitbp->bundleheight);
if ( (fp= fopen(fname,"wb")) != 0 )
{
bundleheight = emitbp->bundleheight;
for (i=n=0; i<emitbp->n&&i<coin->chain->bundlesize; i++)
if ( (block= emitbp->blocks[i]) != 0 && block->txdata != 0 && block->mapped == 0 )
n++;
if ( n != emitbp->n && n != coin->chain->bundlesize )
printf("iguana_emittxdata: WARNING n.%d != bundlesize.%d bundlesize.%d\n",n,emitbp->n,coin->chain->bundlesize);
memset(offsets,0,sizeof(offsets));
if ( (len= fwrite(offsets,sizeof(*offsets),n+1,fp)) != n+1 )
printf("%s: error writing blank offsets len.%ld != %d\n",fname,len,n+1);
for (i=0; i<n; i++)
{
offsets[i] = (uint32_t)ftell(fp);
height = (bundleheight + i);
if ( (block= emitbp->blocks[i]) != 0 )
{
if ( (req= block->txdata) != 0 && (numtx= block->txn_count) > 0 )
{
if ( 0 && fwrite(req->serialized,1,req->n,fp) != req->n )
printf("error writing serialized data.%d\n",req->n);
if ( 0 && (txarray= iguana_gentxarray(coin,&len2,block,req->serialized,req->n,extra)) != 0 )
{
tx = txarray;
for (j=0; j<numtx; j++,tx++)
printf("(%p[%d] %p[%d]) ",tx->vouts,tx->tx_out,tx->vins,tx->tx_in);
printf("emit.%d txarray.%p[%d]\n",i,txarray,numtx);
iguana_emittxarray(coin,fp,block,txarray,numtx);
iguana_freetx(txarray,numtx);
}
} else printf("emittxdata: unexpected missing txarray[%d]\n",i);
} else printf("emittxdata: error with recvblockptr[%d]\n",emitbp->bundleheight + i);
}
offsets[i] = (uint32_t)ftell(fp);
rewind(fp);
if ( (len= fwrite(offsets,sizeof(*offsets),n+1,fp)) != n+1 )
printf("%s: error writing offsets len.%ld != %d\n",fname,len,n+1);
fclose(fp), fp = 0;
memset(&M,0,sizeof(M));
//if ( iguana_maptxdata(coin,&M,emitbp,fname) != n )
// printf("emit error mapping n.%d height.%d\n",n,bundleheight);
//else
{
//if ( emitbp->blockhashes != 0 )
// myfree(emitbp->blockhashes,sizeof(*emitbp->blockhashes) * emitbp->n);
//emitbp->blockhashes = 0;
}
}
}*/
//static uint64_t Tx_allocated,Tx_allocsize,Tx_freed,Tx_freesize;
/*int64_t iguana_MEMallocated(struct iguana_info *coin)
{
int64_t total = coin->TMPallocated;
if ( Tx_allocsize > Tx_freesize )
total += (Tx_allocsize - Tx_freesize);
//total += coin->R.RSPACE.openfiles * coin->R.RSPACE.size;
//total += iguana_packetsallocated(coin);
return(total);
}*/
static int32_t _sort_by_bits256(struct iguana_kvitem *a,struct iguana_kvitem *b)
{
return(bits256_cmp(*(bits256 *)a->keyvalue,*(bits256 *)b->keyvalue));
}
static int32_t _sort_by_revbits256(struct iguana_kvitem *a,struct iguana_kvitem *b)
{
return(bits256_revcmp(*(bits256 *)a->keyvalue,*(bits256 *)b->keyvalue));
}
static int32_t _sort_by_rmd160(struct iguana_kvitem *a,struct iguana_kvitem *b)
{
return(rmd160_cmp(a->keyvalue,b->keyvalue));
}
static int32_t _sort_by_revrmd160(struct iguana_kvitem *a,struct iguana_kvitem *b)
{
return(rmd160_revcmp(a->keyvalue,b->keyvalue));
}
// HASH_SORT(coin->blocks.hash,_sort_by_txid);
/* if ( bp->type == 'Q' )
{
req = (struct iguana_bundlereq *)ptr;
//printf("START.%p save tmp txdata %p [%d].%d datalen.%d %p\n",req,req->argbp,req->argbp!=0?req->argbp->hdrsi:-1,req->argbundlei,req->datalen,req->data);
if ( fp != 0 )
{
if ( fwrite(req->data,1,req->datalen,fp) != req->datalen )
printf("error writing [%d].%d datalen.%d\n",req->argbp!=0?req->argbp->hdrsi:-1,req->argbundlei,req->datalen);
}
//Tx_freed++;
//Tx_freesize += req->allocsize;
if ( req->data != 0 )
myfree(req->data,req->datalen);
if ( req->blocks != 0 )
myfree(req->blocks,sizeof(*req->blocks));
myfree(req,req->allocsize);
}
else if ( bp->type == 'E' )
{
fflush(fp);
//myallocated(0,0);
//iguana_emittxdata(bp->coin,bp);
//myallocated(0,0);
}
else
{
printf("iguana_helper: unsupported type.%c %d %p\n",bp->type,bp->type,bp);
}*/
for (j=0; j<numdirs; j++)
{
finished = 0;
if ( (dir= iguana_peerdirptrHT(coin,&num,inds[j][0],inds[j][1],1)) != 0 )
{
for (i=0; i<num; i++)
{
if ( (itembp= iguana_bundlesearch(coin,&bundlei,dir[i].hash2)) != 0 )
{
//printf("dir[i.%d] j.%d %s %d[%d] %u\n",i,j,bits256_str(str,dir[i].hash2),itembp->hdrsi,bundlei,itembp->emitfinish);
if ( itembp->emitfinish != 0 )
finished++;
}
}
if ( finished == num )
iguana_peerfilecloseHT(coin,inds[j][0],inds[j][1]);
else printf("peerdir.(%d %d) finished.%d of %d\n",inds[j][0],inds[j][1],finished,num);
} else printf("cant get peerdirptr.(%d %d)\n",inds[j][0],inds[j][1]);
}
int32_t iguana_bundlesaveHT(struct iguana_info *coin,struct iguana_memspace *mem,struct iguana_memspace *memB,struct iguana_bundle *bp) // helper thread
{
void *ptrs[IGUANA_MAXBUNDLESIZE]; uint32_t inds[IGUANA_MAXBUNDLESIZE][2]; struct iguana_fileitem *dir;
struct iguana_bundle *itembp; int32_t addrind,bundlei,finished,fileind,i,j,maxrecv,num,flag,numdirs=0;
struct iguana_txdatabits txdatabits; struct iguana_ramchain *ramchain; uint64_t estimatedsize = 0;
struct iguana_block *block;
memset(ptrs,0,sizeof(ptrs)), memset(inds,0,sizeof(inds));
flag = maxrecv = 0;
for (i=0; i<bp->n && i<coin->chain->bundlesize; i++)
{
if ( (block= bp->blocks[i]) != 0 )
{
txdatabits = block->txdatabits;
if ( memcmp(block->hash2.bytes,coin->chain->genesis_hashdata,sizeof(bits256)) == 0 )
ptrs[i] = coin->chain->genesis_hashdata, flag++;
else if ( (ptrs[i]= iguana_peerfileptrHT(coin,txdatabits,1)) != 0 )
{
if ( block->recvlen > maxrecv )
maxrecv = block->recvlen;
estimatedsize += block->recvlen;
flag++;
}
else
{
printf("peerfileptr[%d] (%d %d %d %d) null bp.%p %d\n",i,txdatabits.addrind,txdatabits.filecount,txdatabits.fpos,txdatabits.datalen,bp,bp->hdrsi);
if ( 1 )
{
CLEARBIT(bp->recv,i);
bp->issued[i] = 0;
memset(&block->txdatabits,0,sizeof(block->txdatabits));
block = 0;
}
}
addrind = txdatabits.addrind, fileind = txdatabits.filecount;
if ( numdirs > 0 )
{
for (j=0; j<numdirs; j++)
{
if ( inds[j][0] == addrind && inds[j][1] == fileind )
break;
}
} else j = 0;
if ( j == numdirs )
{
inds[j][0] = addrind;
inds[j][1] = fileind;
numdirs++;
}
}
}
if ( flag == i )
{
iguana_meminit(mem,"bundleHT",0,estimatedsize + IGUANA_MAXPACKETSIZE,0);
iguana_meminit(memB,"ramchainB",0,maxrecv + IGUANA_MAXPACKETSIZE,0);
printf(">>>>>>>>> start MERGE.(%ld %ld) numdirs.%d i.%d flag.%d estimated.%ld maxrecv.%d\n",(long)mem->totalsize,(long)memB->totalsize,numdirs,i,flag,(long)estimatedsize,maxrecv);
if ( (ramchain= iguana_bundlemergeHT(coin,mem,memB,ptrs,i,bp)) != 0 )
{
iguana_ramchainsave(coin,mem,ramchain);
iguana_ramchainfree(coin,mem,ramchain);
bp->emitfinish = (uint32_t)time(NULL);
} else bp->emitfinish = 0;
iguana_mempurge(mem);
iguana_mempurge(memB);
}
else
{
printf(">>>>> bundlesaveHT error: numdirs.%d i.%d flag.%d\n",numdirs,i,flag);
bp->emitfinish = 0;
}
return(flag);
}
int32_t iguana_peerfilecloseHT(struct iguana_info *coin,uint32_t addrind,uint32_t filecount)
{
char fname[512]; int32_t i,n = 0; struct iguana_mappedptr *M;
return(0);
iguana_peerfilename(coin,fname,addrind,filecount);
printf("PEERFILECLOSE.%s\n",fname);
//portable_mutex_lock(&coin->peers.filesM_mutex);
if ( coin->peers.filesM != 0 )
{
for (i=0; i<coin->peers.numfilesM; i++)
{
M = &coin->peers.filesM[i];
if ( strcmp(fname,M->fname) == 0 && M->fileptr != 0 )
{
printf("[%d] closemap.(%s)\n",i,fname);
iguana_closemap(M);
M->closetime = (uint32_t)time(NULL);
n++;
}
}
}
//portable_mutex_unlock(&coin->peers.filesM_mutex);
return(n);
}
void *_iguana_txdataptrHT(struct iguana_info *coin,struct iguana_mappedptr *M,char *fname,struct iguana_txdatabits txdatabits)
{
int32_t len; uint8_t *rawptr; uint32_t starttime = (uint32_t)time(NULL);
if ( M->fileptr != 0 )
{
while ( M->allocsize < (txdatabits.fpos + txdatabits.datalen + sizeof(uint32_t)) )
{
iguana_closemap(M);
if ( iguana_mappedptr(0,M,0,0,fname) == 0 || M->allocsize < (txdatabits.fpos + txdatabits.datalen + sizeof(uint32_t)) )
{
if ( time(NULL) > starttime+3 )
{
printf("too small (%s) %llu vs %ld\n",fname,(long long)M->allocsize,(txdatabits.fpos + txdatabits.datalen + sizeof(uint32_t)));
return(0);
} else sleep(1);
}
}
rawptr = (void *)((long)M->fileptr + txdatabits.fpos);
memcpy(&len,rawptr,sizeof(len));
if ( len == IGUANA_MARKER )
{
memcpy(&len,&rawptr[sizeof(len)],sizeof(len));
//printf("found marker %s[%u] numblocks.%d\n",fname,(int32_t)txdatabits.fpos,len);
if ( txdatabits.isdir != 0 )
return(&rawptr[sizeof(uint32_t)*2]);
else printf("isdir notset with IGUANA_MARKER.%x\n",IGUANA_MARKER);
}
else if ( len == txdatabits.datalen && len < IGUANA_MAXPACKETSIZE )
{
if ( txdatabits.isdir == 0 )
return(&rawptr[sizeof(uint32_t)]);
else printf("isdir set without IGUANA_MARKER.%x\n",IGUANA_MARKER);
} else printf("txdataptr.%s: len.%d error [%d %d %d %d] (%d %d)\n",fname,len,txdatabits.datalen,txdatabits.addrind,txdatabits.fpos,txdatabits.filecount,len == txdatabits.datalen,len < IGUANA_MAXPACKETSIZE);//, getchar();
} //else printf("txdataptr.%s %p %ld vs %ld\n",M->fname,M->fileptr,M->allocsize,(txdatabits.fpos + txdatabits.datalen + sizeof(uint32_t)));
return(0);
}
#define IGUANA_MARKER 0x07770777
void iguana_peerfilename(struct iguana_info *coin,char *fname,uint32_t addrind,uint32_t filecount)
{
sprintf(fname,"tmp/%s/peer%d.%d",coin->symbol,addrind,filecount);
}
struct iguana_txdatabits iguana_calctxidbits(uint32_t addrind,uint32_t filecount,uint32_t fpos,uint32_t datalen)
{
struct iguana_txdatabits bits;
if ( (bits.addrind= addrind) != addrind )
printf("iguana_calctxidbits: addrind overflow.%d\n",addrind), exit(-1);
if ( (bits.filecount= filecount) != filecount )
printf("iguana_calctxidbits: filecount overflow.%d\n",filecount), exit(-1);
if ( (bits.fpos= fpos) != fpos )
printf("iguana_calctxidbits: fpos overflow.%d\n",fpos), exit(-1);
if ( (bits.datalen= datalen) != datalen )
printf("iguana_calctxidbits: datalen overflow.%d\n",datalen), exit(-1);
return(bits);
}
void *iguana_peerfileptrHT(struct iguana_info *coin,struct iguana_txdatabits txdatabits,int32_t createflag)
{
char fname[512]; int32_t i,oldesti,oldest,duration,datalen; uint64_t fpos; struct iguana_mappedptr *M = 0; void *ptr = 0;
fpos = txdatabits.fpos, datalen = txdatabits.datalen;
oldesti = -1;
oldest = 0;
iguana_peerfilename(coin,fname,txdatabits.addrind,txdatabits.filecount);
//portable_mutex_lock(&coin->peers.filesM_mutex);
if ( coin->peers.filesM != 0 )
{
for (i=0; i<coin->peers.numfilesM; i++)
{
M = &coin->peers.filesM[i];
if ( strcmp(fname,M->fname) == 0 )
{
if ( M->fileptr != 0 && (ptr= _iguana_txdataptrHT(coin,M,fname,txdatabits)) != 0 )
{
//portable_mutex_unlock(&coin->peers.filesM_mutex);
//printf("peerfileptr.(%s) %d %d -> %p\n",fname,txdatabits.addrind,txdatabits.filecount,ptr);
return(ptr);
}
else if ( M->closetime != 0 )
{
duration = (uint32_t)(time(NULL) - M->closetime);
if ( duration > oldest )
oldest = duration, oldesti = i;
}
}
}
M = 0;
}
if ( createflag != 0 )
{
if ( oldesti >= 0 && oldest > 60 )
{
M = &coin->peers.filesM[oldesti];
printf("oldesti.%d oldest.%d remove.(%s) recycle slot.%d\n",oldesti,oldest,M->fname,i);
iguana_removefile(M->fname,0);
memset(M,0,sizeof(*M));
}
if ( M == 0 )
{
coin->peers.filesM = myrealloc('m',coin->peers.filesM,coin->peers.filesM==0?0:coin->peers.numfilesM * sizeof(*coin->peers.filesM),(coin->peers.numfilesM+1) * sizeof(*coin->peers.filesM));
M = &coin->peers.filesM[coin->peers.numfilesM];
coin->peers.numfilesM++;
//if ( (coin->peers.numfilesM % 10) == 0 )
printf("iguana_peerfileptr realloc filesM.%d\n",coin->peers.numfilesM);
}
if ( iguana_mappedptr(0,M,0,0,fname) != 0 )
{
ptr = _iguana_txdataptrHT(coin,M,fname,txdatabits);
printf("mapped.(%s) size.%ld %p\n",fname,(long)M->allocsize,ptr);
} else printf("iguana_peerfileptr error mapping.(%s)\n",fname);
}
//portable_mutex_unlock(&coin->peers.filesM_mutex);
return(ptr);
}
struct iguana_fileitem *iguana_peerdirptrHT(struct iguana_info *coin,int32_t *nump,uint32_t addrind,uint32_t filecount,int32_t createflag)
{
char fname[512]; FILE *fp; uint32_t dirpos,marker; struct iguana_txdatabits txdatabits;
*nump = 0;
if ( filecount >= coin->peers.active[addrind].filecount )
return(0);
iguana_peerfilename(coin,fname,addrind,filecount);
if ( (fp= fopen(fname,"rb")) != 0 )
{
fseek(fp,-sizeof(int32_t) * 3,SEEK_END);
fread(nump,1,sizeof(*nump),fp);
fread(&dirpos,1,sizeof(dirpos),fp);
fread(&marker,1,sizeof(marker),fp);
if ( marker == IGUANA_MARKER && (dirpos + sizeof(uint32_t) * 5 + *nump * sizeof(struct iguana_fileitem)) == ftell(fp) )
{
txdatabits = iguana_calctxidbits(addrind,filecount,dirpos,(int32_t)(*nump * sizeof(struct iguana_fileitem)));
fclose(fp);
txdatabits.isdir = 1;
return(iguana_peerfileptrHT(coin,txdatabits,1));
}
else //if ( marker == IGUANA_MARKER )
printf("marker.%x vs %x: dirpos.%d num.%d -> %ld vs %ld\n",marker,IGUANA_MARKER,dirpos,*nump,dirpos + sizeof(uint32_t) * 4 + *nump * sizeof(struct iguana_fileitem),ftell(fp));
fclose(fp);
} else printf("cant open dir.(%s)\n",fname);
return(0);
}
struct iguana_txdatabits iguana_peerfilePT(struct iguana_info *coin,struct iguana_peer *addr,bits256 hash2,struct iguana_txdatabits txdatabits,int32_t datalen)
{
char fname[512]; int32_t marker; uint32_t dirpos;
if ( bits256_nonz(hash2) == 0 || addr->fp == 0 || ftell(addr->fp)+datalen >= IGUANA_PEERFILESIZE-IGUANA_MAXPACKETSIZE || addr->numfilehash2 >= addr->maxfilehash2 )
//if ( addr->fp == 0 )
{
if ( addr->fp != 0 )
{
dirpos = (uint32_t)ftell(addr->fp);
marker = IGUANA_MARKER;
fwrite(&marker,1,sizeof(marker),addr->fp);
fwrite(&addr->numfilehash2,1,sizeof(addr->numfilehash2),addr->fp);
fwrite(addr->filehash2,addr->numfilehash2,sizeof(*addr->filehash2),addr->fp);
fwrite(&addr->numfilehash2,1,sizeof(addr->numfilehash2),addr->fp);
fwrite(&dirpos,1,sizeof(dirpos),addr->fp);
fwrite(&marker,1,sizeof(marker),addr->fp);
fclose(addr->fp);
//iguana_flushQ(coin,addr);
//fflush(addr->fp);
}
iguana_peerfilename(coin,fname,addr->addrind,++addr->filecount);
txdatabits.filecount = addr->filecount;
addr->fp = fopen(fname,"wb");
addr->numfilehash2 = 0;
}
if ( addr->fp == 0 )
{
printf("error creating fileind.%d %s\n",addr->filecount,addr->ipaddr);
exit(1);
}
if ( addr->numfilehash2 < addr->maxfilehash2 )
{
if ( addr->filehash2 == 0 )
addr->filehash2 = mycalloc('f',addr->maxfilehash2,sizeof(*addr->filehash2));
addr->filehash2[addr->numfilehash2].hash2 = hash2;
addr->filehash2[addr->numfilehash2].txdatabits = txdatabits;
addr->numfilehash2++;
}
return(txdatabits);
}
int32_t iguana_ramchainspend(struct iguana_info *coin,struct iguana_ramchain *ramchain,uint32_t spendind,uint32_t spent_txidind,uint16_t spent_vout,int32_t updateflag)
{
struct iguana_pkhash *p; struct iguana_unspent *u; struct iguana_account *acct; int32_t unspentind,pkind;
if ( spent_txidind < ramchain->numtxids )
{
unspentind = (spent_txidind + spent_vout);
u = &ramchain->U[unspentind];
if ( (pkind= u->pkind) < ramchain->numpkinds && pkind >= 0 )
{
if ( updateflag != 0 )
{
p = &ramchain->P[pkind];
if ( ramchain->pkextras[pkind].firstspendind == 0 )
ramchain->pkextras[pkind].firstspendind = spendind;
acct = &ramchain->accounts[pkind];
ramchain->S[spendind].prevspendind = acct->lastspendind;
acct->lastspendind = spendind;
if ( ramchain->Uextras[unspentind].spendind != 0 )
{
printf("double spend u.%d has spendind.%d when s.%d refers to it\n",unspentind,ramchain->Uextras[unspentind].spendind,spendind);
return(-1);
}
ramchain->Uextras[unspentind].spendind = spendind;
}
return(1);
}
}
return(0);
}
int32_t iguana_ramchainspends(struct iguana_info *coin,struct iguana_ramchain *ramchain,int32_t updateflag)
{
struct iguana_spend *s; int32_t j,spendind,retval,spent_txidind,spent_vout,needtxidinds = 0;
spendind = 0;
for (j=0; j<ramchain->numspends; j++,spendind++)
{
s = &ramchain->S[spendind];
spent_txidind = (s->unspentind >> 16) & 0xffff;
spent_vout = (s->unspentind & 0xffff);
if ( (retval= iguana_ramchainspend(coin,ramchain,spendind,spent_txidind,spent_vout,updateflag)) < 0 )
return(-1);
needtxidinds += retval;
}
return(needtxidinds);
}
int32_t iguana_ramchainload(struct iguana_info *coin,struct iguana_memspace *mem,struct iguana_ramchain *ramchain)
{
int32_t i,j; uint32_t unspentind,spendind,txidind,pkind,needtxidinds = 0;
struct iguana_txid *tx; struct iguana_pkhash *p; struct iguana_unspent *u; struct iguana_account *acct;
txidind = unspentind = spendind = pkind = 0;
for (pkind=0; pkind<ramchain->numpkinds; pkind++)
{
p = &ramchain->P[pkind];
iguana_hashsetHT(ramchain->pkhashes,0,p->rmd160,sizeof(p->rmd160),pkind);
}
for (i=0; i<ramchain->numtxids; i++,txidind++)
{
tx = &ramchain->T[txidind];
iguana_hashsetHT(ramchain->txids,0,tx->txid.bytes,sizeof(bits256),txidind);
for (j=0; j<tx->numvouts; j++,unspentind++)
{
u = &ramchain->U[unspentind];
acct = &ramchain->accounts[u->pkind];
u->prevunspentind = acct->lastunspentind;
acct->lastunspentind = unspentind;
if ( u->txidind != txidind )
{
printf("txidind.%d u->txidind.%d mismatch\n",txidind,u->txidind);
return(-1);
}
acct->balance += u->value;
}
}
if ( (needtxidinds= iguana_ramchainspends(coin,ramchain,0)) == 0 )
{
if ( (needtxidinds= iguana_ramchainspends(coin,ramchain,1)) != 0 )
printf("ramchainspends unexpected error\n");
}
return(needtxidinds);
}
int32_t iguana_ramchainload(struct iguana_info *coin,struct iguana_memspace *mem,struct iguana_ramchain *ramchain)
{
int32_t i,j; uint32_t unspentind,spendind,txidind,pkind,needtxidinds = 0;
struct iguana_txid *tx; struct iguana_pkhash *p; struct iguana_unspent *u; struct iguana_account *acct;
txidind = unspentind = spendind = 0;
for (i=0; i<ramchain->numtxids; i++,txidind++)
{
tx = &ramchain->T[txidind];
iguana_hashsetHT(ramchain->txids,0,tx->txid.bytes,sizeof(bits256),txidind);
for (j=0; j<tx->numvouts; j++,unspentind++)
{
}
}
if ( (needtxidinds= iguana_ramchainspends(coin,ramchain,0)) == 0 )
{
if ( (needtxidinds= iguana_ramchainspends(coin,ramchain,1)) != 0 )
printf("ramchainspends unexpected error\n");
}
return(needtxidinds);
}
int32_t iguana_ramchainspend(struct iguana_info *coin,struct iguana_ramchain *ramchain,uint32_t spendind,uint32_t spent_txidind,uint16_t spent_vout,int32_t updateflag)
{
struct iguana_pkhash *p; struct iguana_unspent *u; struct iguana_account *acct; int32_t unspentind,pkind;
if ( spent_txidind < ramchain->numtxids )
{
unspentind = (spent_txidind + spent_vout);
u = &ramchain->U[unspentind];
if ( (pkind= u->pkind) < ramchain->numpkinds && pkind >= 0 )
{
if ( updateflag != 0 )
{
p = &ramchain->P[pkind];
if ( ramchain->pkextras[pkind].firstspendind == 0 )
ramchain->pkextras[pkind].firstspendind = spendind;
acct = &ramchain->accounts[pkind];
ramchain->S[spendind].prevspendind = acct->lastspendind;
acct->lastspendind = spendind;
if ( ramchain->Uextras[unspentind].spendind != 0 )
{
printf("double spend u.%d has spendind.%d when s.%d refers to it\n",unspentind,ramchain->Uextras[unspentind].spendind,spendind);
return(-1);
}
ramchain->Uextras[unspentind].spendind = spendind;
}
return(1);
}
}
return(0);
}
uint32_t oldiguana_rwiAddrind(struct iguana_info *coin,int32_t rwflag,struct iguana_iAddr *iA,uint32_t ind)
{
uint32_t tmpind; char ipaddr[64]; struct iguana_iAddr checkiA;
if ( rwflag == 0 )
{
memset(iA,0,sizeof(*iA));
if ( iguana_kvread(coin,coin->iAddrs,0,iA,&ind) != 0 )
{
//printf("read[%d] %x -> status.%d\n",ind,iA->ipbits,iA->status);
return(ind);
} else printf("error getting pkhash[%u] when %d\n",ind,coin->numiAddrs);
}
else
{
expand_ipbits(ipaddr,iA->ipbits);
tmpind = ind;
if ( iguana_kvwrite(coin,coin->iAddrs,&iA->ipbits,iA,&tmpind) != 0 )
{
if ( tmpind != ind )
printf("warning: tmpind.%d != ind.%d for %s\n",tmpind,ind,ipaddr);
//printf("iA[%d] wrote status.%d\n",ind,iA->status);
if ( iguana_kvread(coin,coin->iAddrs,0,&checkiA,&tmpind) != 0 )
{
if ( memcmp(&checkiA,iA,sizeof(checkiA)) != 0 )
printf("compare error tmpind.%d != ind.%d\n",tmpind,ind);
}
return(iA->ipbits);
} else printf("error kvwrite (%s) ind.%d tmpind.%d\n",ipaddr,ind,tmpind);
}
printf("iA[%d] error rwflag.%d\n",ind,rwflag);
return(0);
}
struct iguana_peer *iguana_choosepeer(struct iguana_info *coin)
{
int32_t i,j,r,iter; struct iguana_peer *addr;
r = rand();
portable_mutex_lock(&coin->peers_mutex);
if ( coin->MAXPEERS == 0 )
coin->MAXPEERS = IGUANA_MAXPEERS;
if ( coin->peers.numranked > 0 )
{
for (j=0; j<coin->peers.numranked; j++)
{
i = (j + r) % coin->MAXPEERS;
if ( (addr= coin->peers.ranked[i]) != 0 && addr->pendblocks < coin->MAXPENDING && addr->dead == 0 && addr->usock >= 0 )
{
portable_mutex_unlock(&coin->peers_mutex);
return(addr);
}
}
}
portable_mutex_unlock(&coin->peers_mutex);
for (iter=0; iter<2; iter++)
{
for (i=0; i<coin->MAXPEERS; i++)
{
addr = &coin->peers.active[(i + r) % coin->MAXPEERS];
if ( addr->dead == 0 && addr->usock >= 0 && (iter == 1 || addr->pendblocks < coin->MAXPENDING) )
return(addr);
}
}
return(0);
}
void iguana_shutdownpeers(struct iguana_info *coin,int32_t forceflag)
{
#ifndef IGUANA_DEDICATED_THREADS
int32_t i,skip,iter; struct iguana_peer *addr;
if ( forceflag != 0 )
coin->peers.shuttingdown = (uint32_t)time(NULL);
for (iter=0; iter<60; iter++)
{
skip = 0;
for (i=0; i<coin->MAXPEERS; i++)
{
addr = &coin->peers.active[i];
if ( addr->ipbits == 0 || addr->usock < 0 || (forceflag == 0 && addr->dead == 0) )
continue;
if ( addr->startsend != 0 || addr->startrecv != 0 )
{
skip++;
continue;
}
iguana_iAkill(coin,addr,0);
}
if ( skip == 0 )
break;
sleep(1);
printf("iguana_shutdownpeers force.%d skipped.%d\n",forceflag,skip);
}
if ( forceflag != 0 )
coin->peers.shuttingdown = 0;
#endif
}
uint32_t iguana_ipbits2ind(struct iguana_info *coin,struct iguana_iAddr *iA,uint32_t ipbits,int32_t createflag)
{
char ipaddr[64]; struct iguana_kvitem *item; struct iguana_iAddr *tmp;
expand_ipbits(ipaddr,ipbits);
//printf("ipbits.%x %s to ind\n",ipbits,ipaddr);
memset(iA,0,sizeof(*iA));
if ( (item= iguana_hashfind(coin->iAddrs,&ipbits,sizeof(ipbits))) == 0 )
//if ( iguana_kvread(coin,coin->iAddrs,&ipbits,iA,&ind) == 0 )
{
if ( createflag == 0 )
return(0);
tmp = mycalloc('i',1,sizeof(*iA));
*tmp = *iA;
iA->ind = coin->numiAddrs;
iA->ipbits = ipbits;
if ( (item= iguana_hashset(coin->iAddrs,0,&iA->ipbits,sizeof(iA->ipbits),iA->ind)) == 0 )
{
printf("iguana_addr: cant save.(%s)\n",ipaddr);
return(0);
}
else
{
coin->numiAddrs++;
if ( iguana_rwiAddrind(coin,1,iA,iA->ind) == 0 )
printf("error iAddr.%d: created %x %s\n",iA->ind,ipbits,ipaddr);
}
}
else *iA = *(struct iguana_iAddr *)item->keyvalue;
return(iA->ind);
}
int32_t iguana_set_iAddrheight(struct iguana_info *coin,uint32_t ipbits,int32_t height)
{
struct iguana_iAddr iA; uint32_t ind;
if ( (ind= iguana_ipbits2ind(coin,&iA,ipbits,1)) > 0 )
{
iA.ipbits = ipbits;
if ( (ind= iguana_rwiAddrind(coin,0,&iA,ind)) > 0 && height > iA.height )
{
iA.height = height;
iA.ipbits = ipbits;
iguana_rwiAddrind(coin,1,&iA,ind);
}
}
return(iA.height);
}
uint32_t iguana_rwipbits_status(struct iguana_info *coin,int32_t rwflag,uint32_t ipbits,int32_t *statusp)
{
struct iguana_iAddr iA; uint32_t ind;
if ( (ind= iguana_ipbits2ind(coin,&iA,ipbits,1)) > 0 )
{
if ( (ind= iguana_rwiAddrind(coin,0,&iA,ind)) > 0 )
{
if ( rwflag == 0 )
*statusp = iA.status;
else
{
iA.status = *statusp;
iA.ipbits = ipbits;
printf("%p status.%d ipbits.%x iA.%d saved iA->ind.%d\n",&iA,iA.status,iA.ipbits,ind,iA.ind);
//printf("set status.%d for ind.%d\n",iA.status,ind);
if ( iguana_rwiAddrind(coin,1,&iA,ind) == 0 )
{
printf("iguana_iAconnected (%x) save error\n",iA.ipbits);
return(0);
}
}
return(ind);
} else printf("iguana_rwiAstatus error getting iA[%d]\n",ind);
} else printf("error ipbits status\n");
return(0);
}
int32_t iguana_ramchainspends(struct iguana_info *coin,struct iguana_ramchain *ramchain,int32_t updateflag)
{
struct iguana_spend *s; int32_t j,spendind,retval,needtxidinds = 0;
spendind = 0;
for (j=0; j<ramchain->numspends; j++,spendind++)
{
s = &ramchain->S[spendind];
if ( (retval= iguana_ramchainspend(coin,ramchain,spendind,s->spendtxidind,s->vout,updateflag)) < 0 )
return(-1);
needtxidinds += retval;
}
return(needtxidinds);
}
if ( bundlei >= coin->chain->bundlesize )
return(block);
if ( (block->bundlei= bundlei) == 0 )
{
iguana_hash2set(coin,"bundlehash2",&bp->blockhashes[0],block->hash2);
//iguana_blockQ(coin,bp,0,bp->bundlehash2,1);
if ( bits256_nonz(block->prev_block) > 0 )
{
//iguana_blockQ(coin,bp,-1,block->prev_block,1);
for (i=0; i<coin->bundlescount; i++)
{
if ( (prevbp= coin->bundles[i]) != 0 && prevbp->n >= coin->chain->bundlesize )
{
cmphash2 = iguana_bundleihash2(coin,prevbp,coin->chain->bundlesize-1);
if ( memcmp(cmphash2.bytes,block->prev_block.bytes,sizeof(bits256)) == 0 )
{
//printf("found prev_block\n");
iguana_hash2set(coin,"bp setprev",&bp->prevbundlehash2,prevbp->blockhashes[0]);
iguana_hash2set(coin,"prevbp setnext",&prevbp->nextbundlehash2,bp->blockhashes[0]);
//printf("prev BUNDLES LINKED! (%d <-> %d) (%s <-> %s)\n",prevbp->bundleheight,bp->bundleheight,bits256_str(prevbp->bundlehash2),bits256_str2(bp->bundlehash2));
if ( prevbp->bundleheight != bp->bundleheight-coin->chain->bundlesize )
printf("WARNING gap in bundleheight %d != %d bundlesize\n",prevbp->bundleheight,bp->bundleheight-coin->chain->bundlesize);
break;
}
}
}
}
}
else if ( bundlei == 1 )
{
if ( iguana_hash2set(coin,"firstblockhash2",&bp->blockhashes[1],block->hash2) < 0 )
return(0);
if ( bp->blockhashes != 0 )
{
if ( bits256_nonz(block->prev_block) > 0 )
iguana_hash2set(coin,"b blockhashes[0]",&bp->blockhashes[0],block->prev_block);
iguana_hash2set(coin,"b blockhashes[1]",&bp->blockhashes[1],block->hash2);
}
}
else if ( bundlei == bp->n-1 )
{
if ( (nextbp= iguana_bundlefind(coin,&nextbundlei,hash2,IGUANA_SEARCHBUNDLE)) != 0 )
{
if ( nextbundlei == 0 )
{
iguana_hash2set(coin,"bp setnext",&bp->nextbundlehash2,nextbp->blockhashes[0]);
iguana_hash2set(coin,"next setprev",&nextbp->prevbundlehash2,bp->blockhashes[0]);
char str[65],str2[65];
bits256_str(str,bp->blockhashes[0]), bits256_str(str2,nextbp->blockhashes[0]);
printf("next BUNDLES LINKED! (%d <-> %d) (%s <-> %s)\n",bp->bundleheight,nextbp->bundleheight,str,str2);
if ( nextbp->bundleheight != bp->bundleheight+coin->chain->bundlesize )
printf("WARNING gap in bundleheight %d != %d bundlesize\n",nextbp->bundleheight,bp->bundleheight+coin->chain->bundlesize);
} else printf("nextbundlei.%d != 0 nextbp->n %d\n",nextbundlei,nextbp->n);
}
//iguana_hash2set(coin,"lastblockhash2",&bp->lastblockhash2,block->hash2);
}
}
struct iguana_bundle *iguana_bundlescan(struct iguana_info *coin,int32_t *bundleip,struct iguana_bundle *bp,bits256 hash2,int32_t searchmask)
{
int32_t i;
*bundleip = -2;
if ( (searchmask & IGUANA_SEARCHBUNDLE) != 0 )
{
// bloom filter here
//printf("%s vs %s: %d\n",bits256_str(hash2),bits256_str2(bp->bundlehash2),memcmp(hash2.bytes,bp->bundlehash2.bytes,sizeof(hash2)));
if ( memcmp(hash2.bytes,bp->blockhashes[0].bytes,sizeof(hash2)) == 0 )
{
*bundleip = 0;
//printf("found blockhash[0]\n");
return(bp);
}
if ( memcmp(hash2.bytes,bp->blockhashes[1].bytes,sizeof(hash2)) == 0 )
{
*bundleip = 1;
//printf("found blockhash[1]\n");
return(bp);
}
for (i=2; i<bp->n && i<coin->chain->bundlesize; i++)
{
if ( memcmp(hash2.bytes,bp->blockhashes[i].bytes,sizeof(hash2)) == 0 )
{
*bundleip = i;
return(bp);
}
}
}
if ( (searchmask & IGUANA_SEARCHPREV) != 0 && memcmp(hash2.bytes,bp->prevbundlehash2.bytes,sizeof(hash2)) == 0 )
{
*bundleip = -1;
return(bp);
}
if ( (searchmask & IGUANA_SEARCHNEXT) != 0 && memcmp(hash2.bytes,bp->nextbundlehash2.bytes,sizeof(hash2)) == 0 )
{
*bundleip = bp->n;
return(bp);
}
return(0);
}
struct iguana_bundle *iguana_bundlefind(struct iguana_info *coin,int32_t *bundleip,bits256 hash2,int32_t adjust)
{
int32_t i,searchmask; struct iguana_bundle *bp = 0; // struct iguana_block *block;
*bundleip = -2;
if ( bits256_nonz(hash2) > 0 )
{
if ( adjust == 0 )
searchmask = IGUANA_SEARCHBUNDLE;
else searchmask = IGUANA_SEARCHNOLAST;
//if ( (block= iguana_blockfind(coin,hash2)) != 0 && (bp= block->bp) != 0 && (bp= iguana_bundlescan(coin,bundleip,bp,hash2,searchmask)) != 0 )
// return(bp);
for (i=0; i<coin->bundlescount; i++)
{
if ( (bp= coin->bundles[i]) != 0 )
{
if ( (bp= iguana_bundlescan(coin,bundleip,bp,hash2,searchmask)) != 0 )
return(bp);
}
}
}
//printf("iguana_hdrsfind: cant find %s\n",bits256_str(hash2));
return(0);
}
int32_t iguana_bundlecheck(struct iguana_info *coin,struct iguana_bundle *bp,int32_t priorityflag)
{
int32_t i,qsize,remains,incomplete,lasti,n = 0; struct iguana_block *block;
bits256 hash2; double threshold; uint64_t datasize =0;
//printf("bp.%p bundlecheck.%d emit.%d\n",bp,bp->ramchain.hdrsi,bp->emitfinish);
if ( bp != 0 && bp->emitfinish == 0 )
{
remains = bp->n - bp->numrecv;
qsize = queue_size(&coin->priorityQ);
if ( bp->numrecv > coin->chain->bundlesize*.98 )
{
priorityflag = 1;
if ( bp->numrecv > coin->chain->bundlesize-3 )
threshold = bp->avetime;
else threshold = bp->avetime * 2;
} else threshold = bp->avetime * 5;
lasti = -1;
for (i=0; i<bp->n && i<coin->chain->bundlesize; i++)
{
hash2 = iguana_bundleihash2(coin,bp,i);
if ( bits256_nonz(hash2) == 0 )
continue;
if ( (block= bp->blocks[i]) == 0 )
block = bp->blocks[i] = iguana_blockfind(coin,hash2);
if ( block != 0 && block->ipbits != 0 )
{
//char str[65];
if ( block->recvlen != 0 )
datasize += block->recvlen;
if ( block->hdrsi != bp->ramchain.hdrsi )
block->hdrsi = bp->ramchain.hdrsi;
if ( block->bundlei != i )
block->bundlei = i;
/* printf("%s %d[%d] != %d[%d]\n",bits256_str(str,block->hash2),block->hdrsi,block->bundlei,bp->ramchain.hdrsi,i);
CLEARBIT(bp->recv,i);
//memset(&bp->blocks[i]->txdatabits,0,sizeof(bp->blocks[i]->txdatabits));
bp->issued[i] = milliseconds();
iguana_blockQ(coin,bp,i,bp->blocks[i]->hash2,1);
bp->blocks[i] = 0;
}
else if ( block->bundlei != i )
{
printf("%s %d[%d] != %d[%d]\n",bits256_str(str,block->hash2),block->hdrsi,block->bundlei,bp->ramchain.hdrsi,i);
CLEARBIT(bp->recv,i);
//memset(&bp->blocks[i]->txdatabits,0,sizeof(bp->blocks[i]->txdatabits));
bp->issued[i] = milliseconds();
iguana_blockQ(coin,bp,i,bp->blocks[i]->hash2,1);
bp->blocks[i] = 0;
} else */
n++;
}
else if ( priorityflag != 0 && qsize == 0 )//&& (bp->issued[i] == 0 || milliseconds() > (bp->issued[i] + threshold)) )
{
//if ( (rand() % 1000) == 0 )
// printf("priorityQ submit threshold %.3f [%d].%d\n",threshold,bp->ramchain.hdrsi,i);
if ( bp->blocks[i] == 0 || bp->blocks[i]->ipbits == 0 )
{
//CLEARBIT(bp->recv,i);
bp->issued[i] = 0;//milliseconds();
//if ( i < 2 )
// iguana_blockQ(coin,bp,i,hash2,1);
//iguana_blockQ(coin,bp,i,hash2,1);
//bp->blocks[i] = 0;
}
lasti = i;
} else lasti = i;
}
//if ( n == coin->chain->bundlesize-1 )
//if ( n > 490 )
// printf("bp.%d %d %d n.%d\n",bp->ramchain.hdrsi,bp->ramchain.bundleheight,lasti,n);
bp->numrecv = n;
bp->datasize = datasize;
if ( n > 0 )
{
bp->estsize = ((uint64_t)datasize * coin->chain->bundlesize) / n;
//printf("estsize %d datasize.%d hdrsi.%d numrecv.%d\n",(int32_t)bp->estsize,(int32_t)datasize,bp->ramchain.hdrsi,n);
}
if ( n == coin->chain->bundlesize )
{
printf("check %d blocks in hdrs.%d\n",n,bp->ramchain.hdrsi);
for (i=incomplete=0; i<n-1; i++)
{
if ( memcmp(bp->blocks[i]->hash2.bytes,bp->blocks[i+1]->prev_block.bytes,sizeof(bits256)) != 0 )
{
if ( bits256_nonz(bp->blocks[i]->prev_block) > 0 && bits256_nonz(bp->blocks[i+1]->prev_block) > 0 && bits256_nonz(bp->blocks[i+1]->hash2) > 0 )
{
char str[65],str2[65],str3[65];
bits256_str(str,bp->blocks[i]->hash2);
bits256_str(str2,bp->blocks[i+1]->prev_block);
bits256_str(str3,bp->blocks[i+1]->hash2);
printf("%s ->%d %d<- %s %s ",str,i,i+1,str2,str3);
printf("broken chain in hdrs.%d %d %p <-> %p %d\n",bp->ramchain.hdrsi,i,bp->blocks[i],bp->blocks[i+1],i+1);
CLEARBIT(bp->recv,i);
//memset(&bp->blocks[i]->txdatabits,0,sizeof(bp->blocks[i]->txdatabits));
//memset(&bp->blocks[i+1]->txdatabits,0,sizeof(bp->blocks[i+1]->txdatabits));
bp->issued[i] = bp->issued[i+1] = milliseconds();
//iguana_blockQ(coin,bp,i,bp->blocks[i]->hash2,1);
//iguana_blockQ(coin,bp,i+1,bp->blocks[i+1]->hash2,1);
bp->blocks[i] = bp->blocks[i+1] = 0;
break;
}
else incomplete++;
}
}
printf("i.%d n.%d incomplete.%d\n",i,n,incomplete);
if ( i == n-1 && incomplete == 0 )
{
//if ( bp->blockhashes != 0 )
//{
for (i=0; i<n; i++)
iguana_hash2set(coin,"check blocks",&bp->blockhashes[i],bp->blocks[i]->hash2);
// iguana_hash2set(coin,"check blockhashes[0]",&bp->blockhashes[0],bp->bundlehash2);
// iguana_hash2set(coin,"check firsthash2",&bp->blockhashes[1],bp->firstblockhash2);
//}
iguana_bundleblockadd(coin,bp,0,iguana_bundleihash2(coin,bp,0));
iguana_bundleblockadd(coin,bp,coin->chain->bundlesize-1,iguana_bundleihash2(coin,bp,coin->chain->bundlesize-1));
if ( bp->emitfinish <= 1 )
iguana_emitQ(coin,bp);
if ( bp->emitfinish == 0 )
bp->emitfinish = 1;
coin->numpendings--;
return(1);
}
}
}
return(0);
}
/******************************************************************************
* Copyright © 2014-2015 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"
// peer context, ie massively multithreaded -> bundlesQ
struct iguana_bundlereq *iguana_bundlereq(struct iguana_info *coin,struct iguana_peer *addr,int32_t type,int32_t datalen)
{
struct iguana_bundlereq *req; int32_t allocsize;
allocsize = (uint32_t)sizeof(*req) + datalen;
req = mycalloc(type,1,allocsize);
req->allocsize = allocsize;
req->datalen = datalen;
req->addr = addr;
req->coin = coin;
req->type = type;
return(req);
}
void iguana_gotblockM(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_txblock *txdata,struct iguana_msgtx *txarray,uint8_t *data,int32_t recvlen)
{
struct iguana_bundlereq *req; int32_t i,z,fpos,bundlei; FILE *fp; char fname[1024];
if ( 0 )
{
for (i=0; i<txdata->space[0]; i++)
if ( txdata->space[i] != 0 )
break;
if ( i != txdata->space[0] )
{
for (i=0; i<txdata->space[0]; i++)
printf("%02x ",txdata->space[i]);
printf("extra\n");
}
}
req = iguana_bundlereq(coin,addr,'B',0);
if ( addr != 0 )
{
if ( addr->pendblocks > 0 )
addr->pendblocks--;
addr->lastblockrecv = (uint32_t)time(NULL);
addr->recvblocks += 1.;
addr->recvtotal += recvlen;
if ( (txdata= iguana_blockramchainPT(coin,addr,txdata,txarray,txdata->block.txn_count,data,recvlen)) != 0 )
{
//fpos = (addr->fp != 0) ? ftell(addr->fp) : 0;
//txdatabits = iguana_calctxidbits(addr->addrind,addr->filecount,(uint32_t)fpos,txdata->datalen);
//txdatabits = iguana_peerfilePT(coin,addr,txdata->block.hash2,txdatabits,txdata->datalen);
fpos = 0;
if ( (bundlei= iguana_peerfname(coin,fname,addr->ipbits,txdata->block.hash2)) < 0 )
{
if ( (fp= fopen(fname,"wb")) != 0 )
coin->peers.numfiles++;
}
else
{
if ( (fp= fopen(fname,"rb+")) == 0 )
{
if ( (fp= fopen(fname,"wb")) != 0 )
{
z = -1;
coin->peers.numfiles++;
for (i=0; i<coin->chain->bundlesize; i++)
fwrite(&z,1,sizeof(z),fp);
fclose(fp);
fp = fopen(fname,"rb+");
}
}
if ( fp != 0 )
{
fseek(fp,0,SEEK_END);
fpos = (int32_t)ftell(fp);
}
}
if ( fp != 0 )
{
txdata->block.bundlei = bundlei;
//printf("fpos.%d: bundlei.%d datalen.%d\n",fpos,bundlei,txdata->datalen);
fwrite(&bundlei,1,sizeof(bundlei),fp);
fwrite(&txdata->block.hash2,1,sizeof(txdata->block.hash2),fp);
fwrite(&txdata->datalen,1,sizeof(txdata->datalen),fp);
fwrite(txdata,1,txdata->datalen,fp);
if ( bundlei >= 0 && bundlei < coin->chain->bundlesize )
{
fseek(fp,bundlei * sizeof(bundlei),SEEK_SET);
//printf("bundlei[%d] <- fpos.%d\n",bundlei,fpos);
fwrite(&fpos,1,sizeof(fpos),fp);
} else printf("error saving with bundlei.%d vs %d\n",bundlei,coin->chain->bundlesize);
fclose(fp);
//for (i=0; i<txdata->numpkinds; i++)
// printf("%016lx ",*(long *)((struct iguana_pkhash *)((long)txdata + txdata->pkoffset))[i].rmd160);
//printf("create.(%s) %d ",fname,bundlei,coin->peers.numfiles);
//printf("bundlei.%d datalen.%d T.%d U.%d S.%d P.%d X.%d\n",bundlei,txdata->datalen,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,txdata->numexternaltxids);
{
struct iguana_txblock *checktxdata; struct iguana_memspace checkmem; int32_t checkbundlei;
memset(&checkmem,0,sizeof(checkmem));
iguana_meminit(&checkmem,"checkmem",0,txdata->block.recvlen + 4096,0);
if ( 0 && (checktxdata= iguana_peertxdata(coin,&checkbundlei,fname,&checkmem,addr->ipbits,txdata->block.hash2)) != 0 )
{
printf("check datalen.%d bundlei.%d T.%d U.%d S.%d P.%d X.%d\n",checktxdata->datalen,checkbundlei,checktxdata->numtxids,checktxdata->numunspents,checktxdata->numspends,checktxdata->numpkinds,checktxdata->numexternaltxids);
}
}
}
req->datalen = txdata->datalen;
}
}
coin->recvcount++;
coin->recvtime = (uint32_t)time(NULL);
req->block = txdata->block;
req->addr = addr;
req->block.txn_count = req->numtx = txdata->block.txn_count;
queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0);
}
void iguana_gottxidsM(struct iguana_info *coin,struct iguana_peer *addr,bits256 *txids,int32_t n)
{
struct iguana_bundlereq *req;
printf("got %d txids from %s\n",n,addr->ipaddr);
req = iguana_bundlereq(coin,addr,'T',0);
req->hashes = txids, req->n = n;
queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0);
}
void iguana_gotunconfirmedM(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_msgtx *tx,uint8_t *data,int32_t datalen)
{
struct iguana_bundlereq *req;
char str[65]; bits256_str(str,tx->txid);
printf("%s unconfirmed.%s\n",addr->ipaddr,str);
req = iguana_bundlereq(coin,addr,'U',datalen);
req->datalen = datalen;
memcpy(req->serialized,data,datalen);
//iguana_freetx(tx,1);
queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0);
}
void iguana_gotheadersM(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_block *blocks,int32_t n)
{
struct iguana_bundlereq *req;
if ( addr != 0 )
{
addr->recvhdrs++;
if ( addr->pendhdrs > 0 )
addr->pendhdrs--;
//printf("%s blocks[%d] ht.%d gotheaders pend.%d %.0f\n",addr->ipaddr,n,blocks[0].height,addr->pendhdrs,milliseconds());
}
req = iguana_bundlereq(coin,addr,'H',0);
req->blocks = blocks, req->n = n;
queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0);
}
void iguana_gotblockhashesM(struct iguana_info *coin,struct iguana_peer *addr,bits256 *blockhashes,int32_t n)
{
struct iguana_bundlereq *req;
if ( addr != 0 )
{
addr->recvhdrs++;
if ( addr->pendhdrs > 0 )
addr->pendhdrs--;
}
req = iguana_bundlereq(coin,addr,'S',0);
req->hashes = blockhashes, req->n = n;
//printf("bundlesQ blockhashes.%p[%d]\n",blockhashes,n);
queue_enqueue("bundlesQ",&coin->bundlesQ,&req->DL,0);
}
// main context, ie single threaded
struct iguana_block *iguana_recvblockhdr(struct iguana_info *coin,struct iguana_bundle **bpp,int32_t *bundleip,struct iguana_block *origblock,int32_t *newhwmp)
{
struct iguana_bundle *prevbp,*bp = 0; int32_t j,prevbundlei; struct iguana_block *block; char str[65];
(*bpp) = 0;
*bundleip = -2;
if ( (block= iguana_blockhashset(coin,-1,origblock->hash2,1)) == 0 )
{
printf("error getting block for %s\n",bits256_str(str,origblock->hash2));
return(0);
}
block->prev_block = origblock->prev_block;
if ( (bp= iguana_bundlefind(coin,bundleip,block->hash2,IGUANA_SEARCHBUNDLE)) == 0 )
{
if ( (prevbp= iguana_bundlefind(coin,&prevbundlei,block->prev_block,IGUANA_SEARCHBUNDLE)) == 0 )
{
printf("cant find prev.%s either\n",bits256_str(str,block->prev_block));
for (j=0; j<coin->bundlescount; j++)
{
if ( (bp= coin->bundles[j]) != 0 )
{
if ( (bp= iguana_bundlescan(coin,bundleip,bp,block->hash2,IGUANA_SEARCHBUNDLE)) != 0 )
{
(*bpp) = bp;
char str[65];
bits256_str(str,block->hash2);
printf("FOUND.%s in bundle.[%d:%d] %d\n",str,bp->ramchain.hdrsi,*bundleip,bp->ramchain.bundleheight + *bundleip);
iguana_bundleblockadd(coin,bp,*bundleip,block->hash2);
return(block);
}
}
}
char str[65];
bits256_str(str,block->hash2);
printf("CANTFIND.%s\n",str);
return(block);
}
else
{
(*bpp) = prevbp;
char str[65];
//printf("found bp.%p prevbundlei.%d\n",prevbp,prevbundlei);
if ( prevbundlei >= 0 && prevbundlei < coin->chain->bundlesize-1 )
{
*bundleip = prevbundlei + 1;
if ( prevbundlei == 0 )
iguana_blockQ(coin,bp,0,block->prev_block,1);
if ( prevbp != 0 )
{
//bits256_str(str,block->hash2);
//printf("prev FOUND.%s in bundle.[%d:%d] %d\n",str,prevbp->ramchain.hdrsi,*bundleip,prevbp->ramchain.bundleheight + *bundleip);
iguana_bundleblockadd(coin,prevbp,*bundleip,block->hash2);
}
}
if ( 0 && prevbundlei == coin->chain->bundlesize-1 )
{
bits256 zero;
memset(zero.bytes,0,sizeof(zero));
bits256_str(str,block->hash2);
printf("prev AUTOCREATE.%s\n",str);
iguana_bundlecreate(coin,block->hash2,zero);
}
return(block);
}
}
else
{
//char str[65],str2[65];
(*bpp) = bp;
//printf("blockadd.%s %s %d\n",bits256_str(str,block->hash2),bits256_str(str2,origblock->hash2),*bundleip);
iguana_bundleblockadd(coin,bp,*bundleip,block->hash2);
if ( *bundleip > 0 && bits256_nonz(block->prev_block) > 0 )
iguana_bundleblockadd(coin,bp,(*bundleip) - 1,block->prev_block);
}
return(block);
}
struct iguana_bundlereq *iguana_recvblockhashes(struct iguana_info *coin,struct iguana_bundlereq *req,bits256 *blockhashes,int32_t num)
{
struct iguana_bundle *bp,*newbp; bits256 zero; int32_t i,j,newbundlei,missing,bundlei = -2,bundleheight = -1;
memset(zero.bytes,0,sizeof(zero));
if ( (bp= iguana_bundlefind(coin,&bundlei,blockhashes[1],IGUANA_SEARCHBUNDLE)) != 0 )
{
if ( bp->blockhashes == 0 )
{
//iguana_blockQ(coin,bp,0,bp->bundlehash2,1);
bundleheight = bp->ramchain.bundleheight;
if ( num > coin->chain->bundlesize+1 )
num = coin->chain->bundlesize+1;
//printf("GOT blockhashes.%s[%d] %d %p hdrsi.%d bundlei.%d\n",bits256_str(str,blockhashes[1]),num,bundleheight,bp->blockhashes,bp->ramchain.hdrsi,bundlei);
memcpy(bp->blockhashes,blockhashes,num * sizeof(*blockhashes));
bp->n = num;
bp->ramchain.bundleheight = bundleheight;
if ( bundlei >= 0 && bundlei < bp->n )
{
j = 1;
if ( bundlei != 1 )
{
/*if ( bundlei == 0 )
{
for (i=1; i<num-1; i++)
blockhashes[i] = blockhashes[i+1];
memset(blockhashes[i].bytes,0,sizeof(bits256));
} else*/
printf("UNEXPECTED >>>>>>>>> hdrsi.%d bundlei.%d j.%d\n",bp->ramchain.hdrsi,bundlei,j);
return(req);
}
for (; j<bp->n && bundlei<=coin->chain->bundlesize; bundlei++,j++)
{
//printf("%d: bundlei.%d %s j.%d\n",bundlei % coin->chain->bundlesize,bundlei,bits256_str(str,blockhashes[j]),j);
if ( bundlei == coin->chain->bundlesize )
{
if ( (newbp= iguana_bundlefind(coin,&newbundlei,blockhashes[j],IGUANA_SEARCHBUNDLE)) == 0 )
{
//iguana_blockQ(coin,newbp,0,blockhashes[j],1);
if ( j < bp->n-1 )
{
newbp = iguana_bundlecreate(coin,blockhashes[j],blockhashes[j+1]);
//iguana_blockQ(coin,newbp,1,blockhashes[j+1],1);
}
else newbp = iguana_bundlecreate(coin,blockhashes[j],zero);
if ( newbp != 0 )
{
char str[65];
if ( bp->ramchain.bundleheight >= 0 )
newbp->ramchain.bundleheight = (bp->ramchain.bundleheight + coin->chain->bundlesize);
init_hexbytes_noT(str,blockhashes[j].bytes,sizeof(bits256));
queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(str),1);
}
}
}
else if ( 1 && iguana_bundleblockadd(coin,bp,bundlei,blockhashes[j]) == 0 )
break;
}
}
//iguana_blockQ(coin,bp,1,blockhashes[1],1);
//if ( bp->n < coin->chain->bundlesize )
// iguana_blockQ(coin,bp,bp->n-1,blockhashes[bp->n-1],1);
//else iguana_blockQ(coin,bp,coin->chain->bundlesize-1,blockhashes[coin->chain->bundlesize-1],1);
}
else
{
if ( num > 2 )
{
for (i=missing=0; i<num && i<bp->n && i<coin->chain->bundlesize; i++)
{
if ( iguana_bundlescan(coin,&bundlei,bp,blockhashes[i],IGUANA_SEARCHBUNDLE) == 0 )
{
missing++;
}
}
if ( missing != 0 )
{
//printf("GOT MISMATCHED %d blockhashes.%s[%d] missing.%d of %d\n",bp->ramchain.bundleheight,bits256_str(blockhashes[1]),num,missing,bp->n);
return(req);
}
if ( num > bp->n && bp->n <= coin->chain->bundlesize )
{
/*myfree(bp->blockhashes,sizeof(*bp->blockhashes) * bp->n);
bp->blockhashes = mycalloc('h',num,sizeof(*blockhashes));
printf("replace blockhashes.%s[%d] %d %p\n",bits256_str(blockhashes[0]),num,bp->ramchain.bundleheight,bp->blockhashes);
memcpy(bp->blockhashes,blockhashes,num * sizeof(*blockhashes));
i = bp->n, bp->n = num;
for (; i<num; i++)
iguana_bundleblockadd(coin,bp,i,blockhashes[i]);*/
return(req);
}
char str[65];
bits256_str(str,blockhashes[1]);
if ( bp->ramchain.bundleheight >= 0 && (rand() % 1000) == 0 )
printf("GOT duplicate.%s[%d] bheight.%d\n",str,num,bp->ramchain.bundleheight);
}
}
if ( (num= bp->n) > coin->chain->bundlesize )
num = coin->chain->bundlesize;
}
else
{
if ( num > coin->chain->bundlesize+1 )
num = coin->chain->bundlesize+1;
//for (i=1; i<num; i++)
// iguana_blockhashset(coin,-1,blockhashes[i],1);
if ( num > 2 )
{
char str[65];
bits256_str(str,blockhashes[1]);
//printf("recvblockhashes cant find %s num.%d\n",str,num);
//iguana_blockQ(coin,0,-1,blockhashes[1],1);
//iguana_bundlecreate(coin,blockhashes[1],blockhashes[2]);
if ( 0 && num == coin->chain->bundlesize+1 && iguana_bundlefind(coin,&bundlei,blockhashes[num - 1],IGUANA_SEARCHBUNDLE) == 0 )
{
bits256 zero;
memset(zero.bytes,0,sizeof(zero));
bits256_str(str,blockhashes[num - 1]);
printf("AUTO EXTEND2.%s[%d]\n",str,num);
iguana_bundlecreate(coin,blockhashes[num - 1],zero);
}
}
}
return(req);
}
struct iguana_bundlereq *iguana_recvblockhdrs(struct iguana_info *coin,struct iguana_bundlereq *req,struct iguana_block *blocks,int32_t n,int32_t *newhwmp)
{
int32_t i,j; struct iguana_block *block; struct iguana_bundle *bp;
if ( blocks == 0 )
return(req);
if ( n > coin->chain->bundlesize+1 )
n = coin->chain->bundlesize+1;
// blockhashes = mycalloc('h',n+1,sizeof(*blockhashes));
// iguana_hash2set(coin,"recvhdrs0",&bp->blockhashes[0],blocks->prev_block);
//for (i=0; i<n; i++)
// iguana_hash2set(coin,"recvhdrs0",&bp->blockhashes[i+1],blocks[i].hash2);
n++;
for (j=0; j<coin->bundlescount; j++)
{
if ( (bp= coin->bundles[j]) != 0 )
{
if ( memcmp(blocks[0].prev_block.bytes,bp->blockhashes[0].bytes,sizeof(bits256)) == 0 )
{
// iguana_hash2set(coin,"recvhdrs0",&bp->blockhashes[0],blocks->prev_block);
//for (i=0; i<n; i++)
// iguana_hash2set(coin,"recvhdrs0",&bp->blockhashes[i+1],blocks[i].hash2);
if ( bp->blockhashes == 0 )
{
bp->n = n < coin->chain->bundlesize ? n : coin->chain->bundlesize;
for (i=1; i<bp->n; i++)
{
iguana_hash2set(coin,"blockhdrs[i]",&bp->blockhashes[i],blocks[i].hash2);
if ( (block= iguana_blockfind(coin,bp->blockhashes[i])) != 0 )
iguana_copyblock(coin,block,&blocks[i-1]);
}
/*iguana_blockQ(coin,bp,0,bp->bundlehash2,1);
iguana_blockQ(coin,bp,1,blockhashes[1],1);
if ( bp->n < coin->chain->bundlesize )
iguana_blockQ(coin,bp,n-1,blockhashes[n-1],1);
else iguana_blockQ(coin,bp,coin->chain->bundlesize-1,blockhashes[coin->chain->bundlesize-1],1);*/
break;
}
else
{
//printf("free duplicate blockhashes\n");
// myfree(blockhashes,n*sizeof(*blockhashes));
}
}
}
}
return(req);
}
struct iguana_bundlereq *iguana_recvblock(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_bundlereq *req,struct iguana_block *origblock,int32_t numtx,int32_t datalen,int32_t *newhwmp)
{
struct iguana_bundle *bp; int32_t bundlei; struct iguana_block *block; double duration = 0.;
if ( (block= iguana_recvblockhdr(coin,&bp,&bundlei,origblock,newhwmp)) != 0 )
{
iguana_copyblock(coin,block,origblock);
//printf("recvblock.(%s) bp.%p bundlei.%d\n",bits256_str(str,block->hash2),bp,bundlei);
if ( bp != 0 && datalen > 0 )
{
//printf("iguana_recvblock (%s) %d[%d] bit.%d recv.%d %02x %02x\n",bits256_str(str,block->hash2),bp->ramchain.hdrsi,bundlei,GETBIT(bp->recv,bundlei),bp->numrecv,bp->recv[0],bp->recv[bp->n/8]);
SETBIT(bp->recv,bundlei);
if ( bp->issued[bundlei] > 0 )
{
duration = (int32_t)(milliseconds() - bp->issued[bundlei]);
if ( duration < bp->avetime/10. )
duration = bp->avetime/10.;
else if ( duration > bp->avetime*10. )
duration = bp->avetime * 10.;
dxblend(&bp->avetime,duration,.9);
dxblend(&coin->avetime,bp->avetime,.9);
}
/*if ( bundlei < 3 )
{
if ( bundlei > 0 )
iguana_blockQ(coin,bp,bundlei-1,block->prev_block,1);
iguana_blockQ(coin,bp,bundlei,block->hash2,1);
}
if ( bundlei == 2 )
{
bp->firstblockhash2 = bp->blockhashes[1] = block->prev_block;
iguana_blockQ(coin,bp,bundlei,block->prev_block,1);
}*/
if ( bundlei >= 0 && bundlei < bp->n && bundlei < coin->chain->bundlesize )
{
if ( 0 && bundlei == 1 )
printf("iguana_recvblock %d[%d] bit.%d recv.%d %02x %02x\n",bp->ramchain.hdrsi,bundlei,GETBIT(bp->recv,bundlei),bp->numrecv,bp->recv[0],bp->recv[bp->n/8]);
if ( req->addr != 0 && req->addr->ipbits != 0 )//&& req->addr->addrind != 0 )
block->ipbits = req->addr->ipbits;
else block->ipbits = 0xffff, printf("null addr\n");
block->recvlen = datalen;
bp->blocks[bundlei] = block;
bp->numrecv++;
//iguana_txdataQ(coin,req,bp,bundlei);
}
//printf("%s hdrsi.%d recv[%d] dur.%.0f avetimes.(%.2f %.2f) numpendinds.%d %f\n",bits256_str(block->hash2),hdrs->hdrsi,bundlei,duration,hdrs->avetime,coin->avetime,coin->numpendings,hdrs->issued[bundlei]);
}
}
else //if ( (rand() % 100) == 0 )
printf("cant create block.%llx\n",(long long)origblock->hash2.txid);
return(req);
}
struct iguana_bundlereq *iguana_recvtxids(struct iguana_info *coin,struct iguana_bundlereq *req,bits256 *txids,int32_t n)
{
return(req);
}
struct iguana_bundlereq *iguana_recvunconfirmed(struct iguana_info *coin,struct iguana_bundlereq *req,uint8_t *data,int32_t datalen)
{
return(req);
}
int32_t iguana_processbundlesQ(struct iguana_info *coin,int32_t *newhwmp) // single threaded
{
int32_t flag = 0; struct iguana_bundlereq *req;
*newhwmp = 0;
while ( flag < 10000 && (req= queue_dequeue(&coin->bundlesQ,0)) != 0 )
{
//printf("%s bundlesQ.%p type.%c n.%d\n",req->addr != 0 ? req->addr->ipaddr : "0",req,req->type,req->n);
if ( req->type == 'B' ) // one block with all txdata
req = iguana_recvblock(coin,req->addr,req,&req->block,req->numtx,req->datalen,newhwmp);
else if ( req->type == 'H' ) // blockhdrs (doesnt have txn_count!)
{
if ( (req= iguana_recvblockhdrs(coin,req,req->blocks,req->n,newhwmp)) != 0 )
{
if ( req->blocks != 0 )
myfree(req->blocks,sizeof(*req->blocks) * req->n), req->blocks = 0;
}
}
else if ( req->type == 'S' ) // blockhashes
{
if ( (req= iguana_recvblockhashes(coin,req,req->hashes,req->n)) != 0 && req->hashes != 0 )
myfree(req->hashes,sizeof(*req->hashes) * req->n), req->hashes = 0;
}
else if ( req->type == 'U' ) // unconfirmed tx
req = iguana_recvunconfirmed(coin,req,req->serialized,req->datalen);
else if ( req->type == 'T' ) // txids from inv
{
if ( (req= iguana_recvtxids(coin,req,req->hashes,req->n)) != 0 )
myfree(req->hashes,(req->n+1) * sizeof(*req->hashes)), req->hashes = 0;
}
else printf("iguana_updatebundles unknown type.%c\n",req->type);
flag++;
if ( req != 0 )
myfree(req,req->allocsize), req = 0;
}
return(flag);
}
int32_t iguana_issueloop(struct iguana_info *coin)
{
static uint32_t lastdisp;
int32_t i,closestbundle,bundlei,qsize,RTqsize,m,numactive,numwaiting,maxwaiting,lastbundle,n,dispflag = 0,flag = 0;
int64_t remaining,closest; struct iguana_bundle *bp,*prevbp,*nextbp; bits256 hash2; struct iguana_block *block;
if ( time(NULL) > lastdisp+13 )
{
dispflag = 1;
lastdisp = (uint32_t)time(NULL);
}
qsize = queue_size(&coin->blocksQ);
if ( qsize == 0 )
coin->bcount++;
else coin->bcount = 0;
maxwaiting = (coin->MAXBUNDLES * coin->chain->bundlesize);
numwaiting = 0;
numactive = 0;
prevbp = nextbp = 0;
lastbundle = -1;
for (i=coin->bundlescount-1; i>=0; i--)
if ( (bp= coin->bundles[i]) != 0 && bp->emitfinish == 0 && bp->blockhashes != 0 )
{
lastbundle = i;
break;
}
if ( lastbundle != coin->lastbundle )
coin->lastbundletime = (uint32_t)time(NULL);
coin->lastbundle = lastbundle;
if ( 0 && time(NULL) < coin->starttime+60 )
lastbundle = -1;
n = 0;
closest = closestbundle = -1;
for (i=0; i<coin->bundlescount; i++)
{
qsize = queue_size(&coin->blocksQ);
m = 0;
if ( (bp= coin->bundles[i]) != 0 )
{
nextbp = (i < coin->bundlescount-1) ? coin->bundles[i+1] : 0;
if ( bp->emitfinish == 0 )
{
//iguana_bundlecheck(coin,bp,numactive == 0 || i == coin->closestbundle || i == lastbundle);
iguana_bundlecheck(coin,bp,i == coin->closestbundle);
if ( bp->numrecv > 3 || numactive == 0 )
{
numactive++;
remaining = (bp->estsize - bp->datasize) + (rand() % (1 + bp->estsize))/100;
if ( remaining > 0 && (closest < 0 || remaining < closest) )
{
//printf("closest.[%d] %d -> R.%d (%d - %d)\n",closestbundle,(int)closest,(int)remaining,(int)bp->estsize,(int)bp->datasize);
closest = remaining;
closestbundle = i;
}
}
//if ( i < (coin->numemitted+coin->MAXPENDING) && numactive >= coin->MAXPENDING && i != coin->closestbundle && i != lastbundle )
continue;
RTqsize = queue_size(&coin->blocksQ);
for (bundlei=0; bundlei<bp->n && bundlei<coin->chain->bundlesize; bundlei++)
{
if ( (block= bp->blocks[bundlei]) != 0 && block->ipbits != 0 )
{
m++;
//printf("hashes.%p numrecv.%d hdrs->n.%d qsize.%d\n",bp->blockhashes,bp->numrecv,bp->n,qsize);
continue;
}
hash2 = iguana_bundleihash2(coin,bp,bundlei);
if ( bits256_nonz(hash2) > 0 )
{
//printf("hdrsi.%d qsize.%d bcount.%d check bundlei.%d bit.%d %.3f lag %.3f ave %.3f\n",bp->ramchain.hdrsi,qsize,coin->bcount,bundlei,GETBIT(bp->recv,bundlei),bp->issued[bundlei],milliseconds() - bp->issued[bundlei],bp->avetime);
if ( (block= bp->blocks[bundlei]) == 0 || block->ipbits == 0 )
//if ( GETBIT(bp->recv,bundlei) == 0 )
{
if ( bp->issued[bundlei] > SMALLVAL )
numwaiting++;
if ( numwaiting < maxwaiting && (bp->issued[bundlei] == 0 || (qsize == 0 && coin->bcount > 100 && milliseconds() > (bp->issued[bundlei] + bp->avetime*2))) )//()) )
{
if ( RTqsize < maxwaiting && (i == lastbundle || i == coin->closestbundle) )
{
char str[65];
bits256_str(str,hash2);
if ( (rand() % 10000) == 0 && bp->issued[bundlei] > SMALLVAL )
printf("issue.%d:%d of %d %s lag %f ave %f\n",bp->ramchain.hdrsi,bundlei,bp->n,str,milliseconds() - bp->issued[bundlei],bp->avetime);
bp->issued[bundlei] = milliseconds();
n++;
flag += (iguana_blockQ(coin,bp,bundlei,hash2,0) > 0);
}
}
}
} //lse printf("skip.%d %s\n",numbundles,bits256_str(hash2));
}
} else m = coin->chain->bundlesize;
}
prevbp = bp;
if ( dispflag != 0 && bp != 0 && bp->emitfinish == 0 && m > 0 )
printf("%s",iguana_bundledisp(coin,prevbp,bp,nextbp,m));
}
//if ( closestbundle >= 0 && (coin->closestbundle < 0 || coin->bundles[coin->closestbundle]->numrecv >= coin->chain->bundlesize) )
coin->closestbundle = closestbundle;
char str[65];
if ( dispflag != 0 )
printf(" PENDINGBUNDLES lastbundle.%d closest.[%d] %s | %d\n",lastbundle,closestbundle,mbstr(str,closest),coin->closestbundle);
return(flag);
}
int32_t iguana_reqhdrs(struct iguana_info *coin)
{
int32_t i,n = 0; struct iguana_bundle *bp; char hashstr[65];
//printf("needhdrs.%d qsize.%d zcount.%d\n",iguana_needhdrs(coin),queue_size(&coin->hdrsQ),coin->zcount);
if ( iguana_needhdrs(coin) > 0 && queue_size(&coin->hdrsQ) == 0 )
{
if ( coin->zcount++ > 10 )
{
for (i=0; i<coin->bundlescount; i++)
{
if ( (bp= coin->bundles[i]) != 0 )
{
if ( time(NULL) > bp->issuetime+7 )//&& coin->numpendings < coin->MAXBUNDLES )
{
if ( bp->issuetime == 0 )
coin->numpendings++;
if ( bp->blockhashes == 0 || bp->n < coin->chain->bundlesize )
{
char str[65];
bits256_str(str,bp->blockhashes[0]);
printf("(%s %d).%d ",str,bp->ramchain.bundleheight,i);
init_hexbytes_noT(hashstr,bp->blockhashes[0].bytes,sizeof(bits256));
queue_enqueue("hdrsQ",&coin->hdrsQ,queueitem(hashstr),1);
n++;
}
bp->issuetime = (uint32_t)time(NULL);
}
}
}
if ( n > 0 )
printf("REQ HDRS pending.%d\n",coin->numpendings);
coin->zcount = 0;
}
} else coin->zcount = 0;
return(n);
}
int32_t iguana_updatecounts(struct iguana_info *coin)
{
int32_t h,flag = 0;
//SETBIT(coin->havehash,0);
//while ( iguana_havetxdata(coin,coin->blocks.recvblocks) != 0 )
// coin->blocks.recvblocks++;
//if ( coin->blocks.recvblocks < 1 )
// coin->blocks.recvblocks = 1;
//while ( GETBIT(coin->havehash,coin->blocks.hashblocks) > 0 )
// coin->blocks.hashblocks++;
h = coin->blocks.hwmheight - coin->chain->bundlesize;
flag = 0;
while ( 0 && iguana_bundleready(coin,h) > 0 )
{
h += coin->chain->bundlesize;
flag++;
}
if ( flag != 0 )
iguana_savehdrs(coin);
return(flag);
}
int32_t iguana_processrecv(struct iguana_info *coin) // single threaded
{
int32_t newhwm = 0,flag = 0;
//printf("process bundlesQ\n");
flag += iguana_processbundlesQ(coin,&newhwm);
//printf("iguana_updatecounts\n");
flag += iguana_updatecounts(coin);
//printf("iguana_reqhdrs\n");
flag += iguana_reqhdrs(coin);
//printf("iguana_issueloop\n");
flag += iguana_issueloop(coin);
//if ( newhwm != 0 )
// flag += iguana_lookahead(coin,&hash2,coin->blocks.hwmheight);
return(flag);
}
struct iguana_block *iguana_recvblockhdr(struct iguana_info *coin,struct iguana_bundle **bpp,int32_t *bundleip,struct iguana_block *origblock,int32_t *newhwmp)
{
struct iguana_bundle *prevbp,*bp = 0; int32_t j,prevbundlei; struct iguana_block *block; char str[65];
(*bpp) = 0;
*bundleip = -2;
if ( (block= iguana_blockhashset(coin,-1,origblock->hash2,1)) == 0 )
{
printf("error getting block for %s\n",bits256_str(str,origblock->hash2));
return(0);
}
block->prev_block = origblock->prev_block;
if ( (bp= iguana_bundlefind(coin,bundleip,block->hash2,IGUANA_SEARCHBUNDLE)) == 0 )
{
if ( (prevbp= iguana_bundlefind(coin,&prevbundlei,block->prev_block,IGUANA_SEARCHBUNDLE)) == 0 )
{
printf("cant find prev.%s either\n",bits256_str(str,block->prev_block));
for (j=0; j<coin->bundlescount; j++)
{
if ( (bp= coin->bundles[j]) != 0 )
{
if ( (bp= iguana_bundlescan(coin,bundleip,bp,block->hash2,IGUANA_SEARCHBUNDLE)) != 0 )
{
(*bpp) = bp;
char str[65];
bits256_str(str,block->hash2);
printf("FOUND.%s in bundle.[%d:%d] %d\n",str,bp->ramchain.hdrsi,*bundleip,bp->ramchain.bundleheight + *bundleip);
iguana_bundleblockadd(coin,bp,*bundleip,block->hash2);
return(block);
}
}
}
char str[65];
bits256_str(str,block->hash2);
printf("CANTFIND.%s\n",str);
return(block);
}
else
{
(*bpp) = prevbp;
char str[65];
//printf("found bp.%p prevbundlei.%d\n",prevbp,prevbundlei);
if ( prevbundlei >= 0 && prevbundlei < coin->chain->bundlesize-1 )
{
*bundleip = prevbundlei + 1;
if ( prevbundlei == 0 )
iguana_blockQ(coin,bp,0,block->prev_block,1);
if ( prevbp != 0 )
{
//bits256_str(str,block->hash2);
//printf("prev FOUND.%s in bundle.[%d:%d] %d\n",str,prevbp->ramchain.hdrsi,*bundleip,prevbp->ramchain.bundleheight + *bundleip);
iguana_bundleblockadd(coin,prevbp,*bundleip,block->hash2);
}
}
if ( 0 && prevbundlei == coin->chain->bundlesize-1 )
{
bits256 zero;
memset(zero.bytes,0,sizeof(zero));
bits256_str(str,block->hash2);
printf("prev AUTOCREATE.%s\n",str);
iguana_bundlecreate(coin,block->hash2,zero);
}
return(block);
}
}
else
{
//char str[65],str2[65];
(*bpp) = bp;
//printf("blockadd.%s %s %d\n",bits256_str(str,block->hash2),bits256_str(str2,origblock->hash2),*bundleip);
iguana_bundleblockadd(coin,bp,*bundleip,block->hash2);
if ( *bundleip > 0 && bits256_nonz(block->prev_block) > 0 )
iguana_bundleblockadd(coin,bp,(*bundleip) - 1,block->prev_block);
}
return(block);
}
/*static int32_t _sort_by_itemind(struct iguana_block *a, struct iguana_block *b)
{
if (a->hh.itemind == b->hh.itemind) return 0;
return (a->hh.itemind < b->hh.itemind) ? -1 : 1;
}*/
int32_t _iguana_verifysort(struct iguana_info *coin)
{
int32_t height,prevheight = -1,i = 0,run = 0; struct iguana_block *block,*tmp;
HASH_ITER(hh,coin->blocks.hash,block,tmp)
{
if ( (height= block->hh.itemind) < 0 )
printf("sortblocks error i.%d height.%d?\n",i,height), getchar();
if ( height <= prevheight )
printf("sortblocks error i.%d height.%d vs prevheight.%d\n",i,height,prevheight), getchar();
if ( height == run )
run++;
i++;
}
printf("_iguana_verifysort: n.%d run.%d\n",i,run);
return(run);
}
/*int32_t iguana_blocksort(struct iguana_info *coin)
{
int32_t hashblocks;
portable_mutex_lock(&coin->blocks_mutex);
HASH_SORT(coin->blocks.hash,_sort_by_itemind);
hashblocks = _iguana_verifysort(coin);
portable_mutex_unlock(&coin->blocks_mutex);
return(hashblocks);
}*/
int32_t _iguana_blocklink(struct iguana_info *coin,struct iguana_block *block)
{
int32_t height,n = 0; struct iguana_block *prev,*next;
if ( block == 0 )
printf("iguana_blockslink: illegal null block %p\n",block), getchar();
block->hh.next = 0, block->hh.prev = 0;
if ( (height= (int32_t)block->hh.itemind) > 0 && (prev= iguana_block(coin,height-1)) != 0 )
{
prev->hh.next = block;
block->hh.prev = prev;
n++;
}
if ( (next= iguana_block(coin,height+1)) != 0 )
{
block->hh.next = next;
next->hh.prev = block;
n++;
}
return(n);
}
/*bits256 iguana_prevblockhash(struct iguana_info *coin,bits256 hash2)
{
struct iguana_block *block; bits256 tmp;
if ( bits256_nonz(hash2) > 0 && (block= iguana_blockfind(coin,hash2)) != 0 )
return(block->prev_block);
else
{
memset(tmp.bytes,0,sizeof(tmp));
return(tmp);
}
}*/
int32_t iguana_hash2height(struct iguana_info *coin,bits256 hash2)
{
struct iguana_block *block;
if ( (block= iguana_blockfind(coin,hash2)) != 0 )
{
if ( block->height >= 0 )
return(block->height);
else return(block->hh.itemind);
}
else return(-1);
}
int32_t iguana_blockheight(struct iguana_info *coin,struct iguana_block *block)
{
struct iguana_block *prev; int32_t height;
if ( (height= iguana_hash2height(coin,block->hash2)) < 0 )
{
if ( (prev= iguana_blockfind(coin,block->prev_block)) != 0 )
{
if ( prev->height >= 0 )
return(prev->height+1);
else if ( (int32_t)prev->hh.itemind >= 0 )
return(prev->hh.itemind + 1);
}
}
return(-1);
}
int32_t iguana_chainheight(struct iguana_info *coin,struct iguana_block *block)
{
if ( block->mainchain != 0 && block->height >= 0 )
return(block->height);
return(-1);
}
void *iguana_blockptr(struct iguana_info *coin,int32_t height)
{
struct iguana_block *block;
if ( height < 0 || height >= coin->blocks.maxbits )
{
//printf("iguana_blockptr height.%d vs maxbits.%d\n",height,coin->blocks.maxbits);
return(0);
}
if ( (block= coin->blocks.ptrs[height]) != 0 )
return(block);
return(0);
}
/*void *iguana_bundletxdata(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei)
{
struct iguana_block *block; void *txdata = 0;
if ( bp != 0 && bundlei >= 0 && bundlei < coin->chain->bundlesize && GETBIT(bp->recv,bundlei) != 0 && (block= bp->blocks[bundlei]) != 0 )
{
txdata = block->txdata;
}
//printf("txdata.%p\n",txdata);
return(txdata);
}*/
int32_t iguana_avail(struct iguana_info *coin,int32_t height,int32_t n)
{
int32_t i,nonz = 0;
for (i=0; i<n; i++)
if ( iguana_blockptr(coin,height+i) != 0 )
nonz++;
return(nonz);
}
/*int32_t iguana_bundleready(struct iguana_info *coin,int32_t height)
{
int32_t i,num = coin->chain->bundlesize;
if ( GETBIT(coin->bundleready,height/num) != 0 )
return(1);
for (i=0; i<num; i++)
if ( iguana_havehash(coin,height+i) <= 0 )
return(0);
SETBIT(coin->bundleready,height/num);
return(1);
}
int32_t iguana_fixblocks(struct iguana_info *coin,int32_t startheight,int32_t endheight)
{
struct iguana_block *block,space,origblock; int32_t height,n = 0;
for (height=startheight; height<=endheight; height++)
{
if ( (block= iguana_block(coin,&space,height)) != 0 )
{
origblock = space;
iguana_setdependencies(coin,block);
if ( memcmp(&origblock,block,sizeof(origblock)) != 0 )
{
printf("%d ",height);
n++;
iguana_kvwrite(coin,coin->blocks.db,0,block,(uint32_t *)&block->height);
}
}
}
iguana_syncmap(&coin->blocks.db->M,0);
return(n);
}
int32_t iguana_blockcmp(struct iguana_info *coin,struct iguana_block *A,struct iguana_block *B,int32_t fastflag)
{
struct iguana_block tmpA,tmpB;
tmpA = *A, tmpB = *B;
memset(&tmpA.L,0,sizeof(tmpA.L)), memset(&tmpB.L,0,sizeof(tmpB.L));
memset(&tmpA.hh,0,sizeof(tmpA.hh)), memset(&tmpB.hh,0,sizeof(tmpB.hh));
tmpA.numvouts = tmpA.numvins = tmpA.tbd = tmpB.numvouts = tmpB.numvins = tmpB.tbd = 0;
if ( memcmp(&tmpA,&tmpB,sizeof(tmpA)) != 0 )
return(-1);
if ( fastflag == 0 )
{
if ( iguana_setdependencies(coin,&tmpA) != iguana_setdependencies(coin,&tmpB) || memcmp(&tmpA,&tmpB,sizeof(tmpA)) == 0 )
return(-1);
}
return(0);
}*/
/*
int32_t iguana_checkblock(struct iguana_info *coin,int32_t dispflag,struct iguana_block *block,bits256 hash2)
{
struct iguana_block checkspace,prevspace,*checkblock,*prev; bits256 prevhash; int32_t retval = 0;
if ( block != 0 )
{
if ( (checkblock= iguana_block(coin,&checkspace,block->height)) == 0 )
{
if ( dispflag != 0 )
printf("cant find checkblock %s at %d\n",bits256_str(hash2),block->height);
return(-2);
}
if ( memcmp(block,checkblock,sizeof(*block)) != 0 )
{
if ( dispflag != 0 )
printf("compare error %s block.%d vs checkblock.%d\n",bits256_str(hash2),block->height,checkblock->height);
return(-3);
}
prevhash = iguana_prevblockhash(coin,hash2);
if ( bits256_nonz(prevhash) != 0 )
{
if ( memcmp(prevhash.bytes,block->prev_block.bytes,sizeof(prevhash)) != 0 )
{
if ( dispflag != 0 )
{
printf("height.%d block->prev %s vs ",block->height,bits256_str(block->prev_block));
printf("prevhash mismatch %s\n",bits256_str(prevhash));
}
return(-4);
}
} else prevhash = block->prev_block;
if ( block->height == 0 )
{
//printf("reached genesis! numvalid.%d from %s\n",numvalid,bits256_str(coin->blocks.best_chain));
return(0);
}
//printf("block.%d\n",block->height);
if ( (prev= iguana_blockfind(coin,&prevspace,prevhash)) == 0 )
{
if ( dispflag != 0 )
printf("cant find prevhash for (%s).%d\n",bits256_str(hash2),block->height);
return(-5);
} //else printf("block->height.%d prev height.%d %s\n",block->height,prev->height,bits256_str(prevhash));
if ( fabs(block->L.PoW - (prev->L.PoW + PoW_from_compact(block->bits,coin->chain->unitval))) > SMALLVAL )
{
if ( dispflag != 0 )
printf("PoW mismatch: %s %.15f != %.15f (%.15f %.15f)\n",bits256_str(hash2),block->L.PoW,(prev->L.PoW + PoW_from_compact(block->bits,coin->chain->unitval)),prev->L.PoW,PoW_from_compact(block->bits,coin->chain->unitval));
block->L.PoW = (prev->L.PoW + PoW_from_compact(block->bits,coin->chain->unitval));
retval = -1000;
}
if ( block->txn_count != 0 && block->L.numtxids != (prev->L.numtxids + prev->txn_count) && block->L.numunspents != (prev->L.numunspents + prev->numvouts) && block->L.numspends != (prev->L.numspends + prev->numvins) )
{
if ( dispflag != 0 )
printf("firsttxidind mismatch %s T%d != %d (%d + %d) || U%d != %d (%d + %d) || S%d != %d (%d + %d)\n",bits256_str(hash2),block->L.numtxids,(prev->L.numtxids + prev->txn_count),prev->L.numtxids,prev->txn_count,block->L.numunspents,(prev->L.numunspents + prev->numvouts),prev->L.numunspents,prev->numvouts,block->L.numspends,(prev->L.numspends + prev->numvins),prev->L.numspends,prev->numvins);
block->L.numtxids = (prev->L.numtxids + prev->txn_count);
block->L.numunspents = (prev->L.numunspents + prev->numvouts);
block->L.numspends = (prev->L.numspends + prev->numvins);
return(retval - 10000);
}
return(retval);
}
if ( dispflag != 0 )
printf("iguana_checkblock: null ptr\n");
return(-8);
}
int32_t _iguana_audit(struct iguana_info *coin)
{
bits256 hash2; struct iguana_block *block,space; int32_t numvalid = 0;
hash2 = coin->blocks.hwmchain;
while ( (block= iguana_blockfind(coin,&space,hash2)) != 0 )
{
if ( iguana_checkblock(coin,1,block,hash2) == 0 )
{
numvalid++;
if ( block->height == 0 )
return(numvalid);
hash2 = block->prev_block;
}
}
printf("iguana_audit numvalid.%d vs %d\n",numvalid,coin->blocks.hwmheight);
return(numvalid);
}
void iguana_audit(struct iguana_info *coin)
{
int32_t numvalid;
if ( (numvalid= _iguana_audit(coin)) < 0 || numvalid != coin->blocks.hwmheight )
{
printf("iguana_audit error.%d\n",numvalid);
iguana_kvdisp(coin,coin->blocks.db);
}
}*/
/*int32_t iguana_lookahead(struct iguana_info *coin,bits256 *hash2p,int32_t height)
{
struct iguana_block space,*block; bits256 hash2; int32_t err,h,n = 0;
while ( (block= iguana_block(coin,&space,height)) != 0 )
{
*hash2p = hash2 = iguana_blockhash(coin,height);
if ( (err= iguana_checkblock(coin,1,block,hash2)) == 0 || err <= -1000 )
{
if ( err < 0 )
{
h = height;
printf("fixup height.%d\n",height);
iguana_kvwrite(coin,coin->blocks.db,hash2.bytes,block,(uint32_t *)&h);
//getchar();
}
if ( (h= iguana_addblock(coin,hash2,block)) != height )
{
printf("height.%d h.%d n.%d didnt work\n",height,h,n);
//getchar();
break;
}
n++;
height++;
coin->blocks.hwmheight = height;
}
else
{
printf("height.%d %s error.%d\n",height,bits256_str(hash2),err);
break;
}
}
printf("lookahead stopped at height.%d\n",height);
return(n);
}
*/
int32_t iguana_setchainvars(struct iguana_info *coin,struct iguana_prevdep *lp,bits256 hash2,uint32_t nBits,bits256 prevhash,int32_t txn_count) // uint32_t *firsttxidindp,uint32_t *firstvoutp,uint32_t *firstvinp,double *PoWp
{
int32_t height=-1,firstvout=0,firstvin=0,firsttxidind=0; double PoW;
struct iguana_prevdep *prevlp; struct iguana_block *prev;
memset(lp,0,sizeof(*lp));
if ( memcmp(coin->chain->genesis_hashdata,hash2.bytes,sizeof(hash2)) == 0 )
{
PoW = PoW_from_compact(nBits,coin->chain->unitval);
height = 0;
firsttxidind = firstvout = firstvin = 1;
printf("set genesis vars nBits.%x\n",nBits);
}
else
{
if ( (prev= iguana_blockfind(coin,prevhash)) == 0 )
{
if ( iguana_needhdrs(coin) == 0 )
{
char str[65],str2[65];
bits256_str(str,hash2);
bits256_str(str2,prevhash);
printf("hash2.(%s) ",str);
fprintf(stderr,"iguana_blockchain no prev block.(%s)\n",str2);
//getchar();
}
return(-1);
}
else
{
height = prev->height + 1;
if ( (prevlp= iguana_prevdepfind(coin,prev)) != 0 )
{
PoW = (PoW_from_compact(nBits,coin->chain->unitval) + prevlp->PoW);
if ( txn_count > 0 && prevlp->numtxids > 0 && prev->numvouts > 0 && prevlp->numunspents > 0 && prevlp->numspends > 0 )
{
firsttxidind = prevlp->numtxids + prev->txn_count;
firstvout = prevlp->numunspents + prev->numvouts;
firstvin = prevlp->numspends + prev->numvins;
//printf("PREV.%d firsttxidind.%d firstvout.%d+%d firstvin.%d+%d (%d %d %d)\n",prev->height,prev->L.numtxids,prev->L.numunspents,prev->numvouts,prev->L.numspends,prev->numvins,firsttxidind,firstvout,firstvin);
}
}
}
}
if ( lp != 0 )
{
lp->PoW = PoW;
lp->numtxids = firsttxidind;
lp->numunspents = firstvout;
lp->numspends = firstvin;
}
//printf("set height.%d: %d %f firstvin.%d firstvout.%d\n",height,firsttxidind,PoW,firstvin,firstvout);
return(height);
}
int32_t iguana_setdependencies(struct iguana_info *coin,struct iguana_block *block,struct iguana_prevdep *lp)
{
int32_t h,height;
if ( block == 0 )
return(-1);
height = block->height;
if ( (h= iguana_setchainvars(coin,lp,block->hash2,block->bits,block->prev_block,block->txn_count)) == height )
{
// place to make sure connected to ramchain
return(height);
}
if ( height < 0 )
block->height = h;
//printf("dependencies returned %d vs %d\n",h,height);
return(-1);
}
int32_t iguana_chainextend(struct iguana_info *coin,struct iguana_block *newblock)
{
int32_t h;
if ( (newblock->height= iguana_setdependencies(coin,newblock,lp)) >= 0 )
{
if ( lp->PoW > coin->blocks.hwmPoW )
{
if ( newblock->height+1 > coin->blocks.maxblocks )
coin->blocks.maxblocks = (newblock->height + 1);
h = newblock->height;
iguana_kvwrite(coin,coin->blocks.db,hash2.bytes,newblock,(uint32_t *)&h);
coin->blocks.hwmheight = newblock->height;
coin->blocks.hwmPoW = lp->PoW;
coin->blocks.hwmchain = hash2;
coin->latest.blockhash = hash2;
coin->latest.merkle_root = newblock->merkle_root;
coin->latest.timestamp = newblock->timestamp;
coin->latest.height = coin->blocks.hwmheight;
char str[65],str2[65];
bits256_str(str,newblock->hash2);
bits256_str(str2,coin->blocks.hwmchain);
printf("ADD %s %d:%d <- (%s) n.%u max.%u PoW %f 1st.%d numtx.%d\n",str,h,newblock->height,str2,coin->blocks.hwmheight+1,coin->blocks.maxblocks,lp->PoW,lp->numtxids,newblock->txn_count);
}
} else printf("error from setchain.%d\n",newblock->height);
if ( memcmp(hash2.bytes,coin->blocks.hwmchain.bytes,sizeof(hash2)) != 0 )
{
char str[65];
bits256_str(str,hash2);
if ( iguana_needhdrs(coin) == 0 )
printf("ORPHAN.%s height.%d PoW %f vs best %f\n",str,newblock->height,lp->PoW,coin->blocks.hwmPoW);
newblock->height = -1;
}
return(newblock->height);
}
else if ( strcmp(H->command,"headers") == 0 )
{
struct iguana_msgblock msg; struct iguana_block *blocks; uint32_t n; struct iguana_prevdep L;
len = iguana_rwvarint32(0,data,&n);
if ( n <= IGUANA_MAXINV )
{
blocks = mycalloc('i',1,sizeof(*blocks) * n);
height = -1;
memset(&L,0,sizeof(L));
for (i=0; i<n; i++)
{
len += iguana_rwblock(0,&hash2,&data[len],&msg);
if ( i == 0 )
height = iguana_setchainvars(coin,&L,hash2,msg.H.bits,msg.H.prev_block,msg.txn_count);
iguana_convblock(&blocks[i],&msg,hash2,height);
if ( L.numtxids > 0 )
{
height++;
L.numtxids += blocks[i].txn_count;
L.PoW += PoW_from_compact(blocks[i].bits,coin->chain->unitval);
}
}
//printf("GOT HEADERS n.%d len.%d\n",n,len);
iguana_gotheadersM(coin,addr,blocks,n);
//myfree(blocks,sizeof(*blocks) * n);
if ( len == datalen && addr != 0 )
addr->msgcounts.headers++;
} else printf("got unexpected n.%d for headers\n",n);
}
/*int32_t iguana_chainheight(struct iguana_info *coin,struct iguana_block *origblock)
{
static const bits256 zero; struct iguana_block *next,*block = origblock;
bits256 *blockhashes; char str[65]; int32_t i,max,toofar=0,height,n=0;
next = origblock;
iguana_memreset(&coin->blockMEM);
max = (int32_t)(coin->blockMEM.totalsize / sizeof(*blockhashes));
blockhashes = iguana_memalloc(&coin->blockMEM,max*sizeof(*blockhashes),1);
while ( memcmp(block->prev_block.bytes,zero.bytes,sizeof(bits256)) != 0 )
{
if ( n < max-1 )
blockhashes[n++] = block->hash2;
else toofar = 1;
if ( (block= iguana_blockfind(coin,block->prev_block)) != 0 )
{
//printf("i.%d %s chainheight.%d mainchain.%d\n",n,bits256_str(str,block->hash2),block->height,block->mainchain);
if ( block->mainchain != 0 && (height= block->height) >= 0 )
{
iguana_chainextend(coin,next);
//printf("%s extend.%d from %d toofar.%d\n",bits256_str(str,block->hash2),n,height,toofar);
if ( toofar == 0 )
{
for (i=0; i<n; i++)
{
if ( (block= iguana_blockfind(coin,blockhashes[n-1-i])) == 0 )
{
printf("%d of %d: cant find block.%s or cant extend\n",i,n,bits256_str(str,blockhashes[n-1-i]));
return(origblock->height);
}
if ( iguana_chainextend(coin,next) < 0 )
{
//printf("%d of %d: cant extend block.%s\n",i,n,bits256_str(str,blockhashes[n-1-i]));
return(origblock->height);
}
next = block;
}
return(origblock->height);
}
//printf("toofar means neg height\n");
return(-1);
}
next = block;
} else break;
} // reached deadend or too far to link in
//printf("out of chainheight loop\n");
return(origblock->height);
}*/
/*int32_t iguana_issueloop(struct iguana_info *coin)
{
static uint32_t lastdisp;
int32_t i,closestbundle,qsize,m,numactive,numwaiting,maxwaiting,lastbundle,n,dispflag = 0,flag = 0;
int64_t remaining,closest; struct iguana_bundle *bp,*prevbp,*nextbp;
flag = iguana_reqhdrs(coin);
if ( time(NULL) > lastdisp+13 )
{
dispflag = 1;
lastdisp = (uint32_t)time(NULL);
}
qsize = queue_size(&coin->blocksQ);
if ( qsize == 0 )
coin->bcount++;
else coin->bcount = 0;
maxwaiting = (coin->MAXBUNDLES * coin->chain->bundlesize);
numwaiting = 0;
numactive = 0;
prevbp = nextbp = 0;
lastbundle = -1;
for (i=coin->bundlescount-1; i>=0; i--)
if ( (bp= coin->bundles[i]) != 0 && bp->emitfinish == 0 && bp->blockhashes != 0 )
{
lastbundle = i;
break;
}
if ( lastbundle != coin->lastbundle )
coin->lastbundletime = (uint32_t)time(NULL);
coin->lastbundle = lastbundle;
if ( 0 && time(NULL) < coin->starttime+60 )
lastbundle = -1;
n = 0;
closest = closestbundle = -1;
for (i=0; i<coin->bundlescount; i++)
{
qsize = queue_size(&coin->blocksQ);
m = 0;
if ( (bp= coin->bundles[i]) != 0 )
{
nextbp = (i < coin->bundlescount-1) ? coin->bundles[i+1] : 0;
if ( bp->emitfinish == 0 )
{
m = (bp->n - bp->numrecv);
if ( bp->numrecv > 3 || numactive == 0 )
{
numactive++;
remaining = (bp->estsize - bp->datasize) + (rand() % (1 + bp->estsize))/100;
if ( remaining > 0 && (closest < 0 || remaining < closest) )
{
//printf("closest.[%d] %d -> R.%d (%d - %d)\n",closestbundle,(int)closest,(int)remaining,(int)bp->estsize,(int)bp->datasize);
closest = remaining;
closestbundle = i;
}
}
if ( dispflag != 0 )
printf("%s",iguana_bundledisp(coin,prevbp,bp,nextbp,m));
}
}
prevbp = bp;
}
//if ( closestbundle >= 0 && (coin->closestbundle < 0 || coin->bundles[coin->closestbundle]->numrecv >= coin->chain->bundlesize) )
coin->closestbundle = closestbundle;
char str[65];
if ( dispflag != 0 )
printf(" PENDINGBUNDLES lastbundle.%d closest.[%d] %s | %d\n",lastbundle,closestbundle,mbstr(str,closest),coin->closestbundle);
return(flag);
}*/
int32_t iguana_updatecounts(struct iguana_info *coin)
{
int32_t flag = 0;
//SETBIT(coin->havehash,0);
//while ( iguana_havetxdata(coin,coin->blocks.recvblocks) != 0 )
// coin->blocks.recvblocks++;
//if ( coin->blocks.recvblocks < 1 )
// coin->blocks.recvblocks = 1;
//while ( GETBIT(coin->havehash,coin->blocks.hashblocks) > 0 )
// coin->blocks.hashblocks++;
return(flag);
}
//printf("iguana_issueloop\n");
//flag += iguana_issueloop(coin);
//if ( newhwm != 0 )
// flag += iguana_lookahead(coin,&hash2,coin->blocks.hwmheight);
/*struct iguana_block *iguana_blockadd(struct iguana_info *coin,struct iguana_bundle **bpp,int32_t *bundleip,struct iguana_block *origblock)
{
struct iguana_block *checkblock,*block = 0; char str[65]; struct iguana_bundle *bp = *bpp;
int32_t setval,checki,bundlei,bundleheight,bundlesize = coin->chain->bundlesize;
bundlei = *bundleip;
*bundleip = -2;
*bpp = 0;
if ( origblock == 0 )
return(0);
//iguana_blockhashset(coin,-1,origblock->prev_block,1);
if ( bits256_nonz(origblock->hash2) > 0 && (block= iguana_blockhashset(coin,-1,origblock->hash2,1)) != 0 )
{
//printf("blockadd.(%s) -> %d (%s)\n",bits256_str(str,origblock->prev_block),block->height,bits256_str(str2,origblock->hash2));
if ( bits256_nonz(block->prev_block) == 0 )
iguana_blockcopy(coin,block,origblock);
if ( (bp= *bpp) == 0 )
{
if ( (bp= iguana_bundlefind(coin,bpp,&bundlei,block->hash2)) == 0 )
{
*bpp = 0, bundlei = -2;
//printf("a bundlefind.(%s) -> bundlei.%d\n",bits256_str(str,block->hash2),*bundleip);
if ( (bp= iguana_bundlefind(coin,bpp,&bundlei,block->prev_block)) == 0 )
{
//iguana_chainheight(coin,block);
//printf("a prev bundlefind.(%s) -> bundlei.%d ht.%d\n",bits256_str(str,block->prev_block),*bundleip,block->height);
*bpp = 0;
*bundleip = -2;
return(block);
}
else
{
if ( *bundleip == bundlesize-1 )
{
printf("b prev bundlefind.(%s) -> bundlei.%d\n",bits256_str(str,block->prev_block),*bundleip);
bundleheight = (bp->ramchain.bundleheight >= 0) ? (bp->ramchain.bundleheight + bundlesize) : -1;
printf("autocreateA: bundleheight.%d\n",bundleheight);
bundlei = -2;
*bpp = bp = iguana_bundlecreate(coin,&bundlei,bundleheight,block->hash2);
*bpp = 0;
*bundleip = -2;
return(block);
}
else if ( bundlei < coin->chain->bundlesize-1 )
{
bundlei++;
if ( bp->n <= bundlei )
bp->n = bundlei+1;
iguana_hash2set(coin,"add",bp,bundlei,block->hash2);
//printf("found prev.%s -> bundlei.%d\n",bits256_str(str,block->prev_block),bundlei);
}
}
}
else
{
// printf("found bp.%p bundlei.%d\n",bp,bundlei);
}
}
else if ( bundlei < -1 )
{
bp = iguana_bundlefind(coin,bpp,&bundlei,block->hash2);
printf("c bundlefind.(%s) -> bundlei.%d\n",bits256_str(str,block->hash2),bundlei);
} else printf("last case bundleip %d\n",bundlei);
*bpp = bp;
*bundleip = bundlei;
//printf("bundlei.%d for %s\n",bundlei,bits256_str(str,block->hash2));
if ( memcmp(bp->hashes[bundlei].bytes,block->hash2.bytes,sizeof(bits256)) != 0 )
printf("honk? find error %s\n",bits256_str(str,bp->hashes[bundlei])), getchar();
if ( bp == 0 || bundlei < -1 )
{
printf("%s null bp? %p or illegal bundlei.%d block.%p\n",bits256_str(str,block->hash2),bp,bundlei,block);
return(block);
}
if ( (setval= iguana_bundlehash2add(coin,&checkblock,bp,bundlei,block->hash2)) == 0 && checkblock == block )
{
if ( bp->blocks[bundlei] != 0 )
{
if ( bp->blocks[bundlei] != block )
printf("blockadd: error blocks[%d] %p %d != %d %p\n",bundlei,bp->blocks[bundlei],bp->blocks[bundlei]->height,block->height,block);
} else bp->blocks[bundlei] = block;
//iguana_bundlehash2add(coin,0,bp,bundlei-1,block->prev_block);
//printf("setval.%d bp.%p bundlei.%d\n",setval,bp,bundlei);
}
else if ( setval > 0 )
{
if ( bundlei == bundlesize )
{
bundleheight = (bp->ramchain.bundleheight >= 0) ? (bp->ramchain.bundleheight + bundlesize) : -1;
printf("autocreate: bundleheight.%d\n",bundleheight);
iguana_bundlecreate(coin,&checki,bundleheight,block->hash2);
}
printf("setval.%d bundlei.%d\n",setval,bundlei);
} else printf("blockadd: error.%d adding hash2, checkblock.%p vs %p\n",setval,checkblock,block);
//printf("bundleblockadd.[%d] of %d <- %s setval.%d %p\n",bundlei,bp->n,bits256_str(str,block->hash2),setval,block);
} else printf("bundleblockadd: block.%p error\n",block);
return(block);
}
struct iguana_block *iguana_bundleblockadd(struct iguana_info *coin,struct iguana_bundle **bpp,int32_t *bundleip,struct iguana_block *origblock)
{
struct iguana_block *block,*retblock; int32_t i,oldhwm; struct iguana_bundle *bp;
bits256 *hash2p,hash2; char str[65]; struct iguana_bloominds bit;
oldhwm = coin->blocks.hwmchain.height;
*bpp = 0, *bundleip = -2;
if ( (retblock= iguana_blockadd(coin,bpp,bundleip,origblock)) != 0 )
{
block = retblock;
//iguana_chainextend(coin,block);
if ( block->height >= 0 && (hash2p= iguana_blockhashptr(coin,coin->blocks.hashblocks)) != 0 )
*hash2p = block->hash2;
if ( oldhwm != coin->blocks.hwmchain.height )
{
if ( oldhwm < coin->blocks.hashblocks )
coin->blocks.hashblocks = oldhwm;
while ( coin->blocks.hashblocks < coin->blocks.hwmchain.height && (hash2p= iguana_blockhashptr(coin,coin->blocks.hashblocks)) != 0 )
{
hash2 = *hash2p;
if ( bits256_nonz(hash2) > 0 && (block= iguana_blockfind(coin,hash2)) != 0 )
{
if ( hash2p == 0 )
{
printf("iguana_bundleblockadd B cant find coin->blocks.hashblocks %d\n",coin->blocks.hashblocks);
break;
}
*hash2p = hash2;
for (i=0; i<coin->bundlescount; i++)
{
if ( (bp= coin->bundles[i]) != 0 )
{
if ( coin->blocks.hashblocks >= bp->ramchain.bundleheight && coin->blocks.hashblocks < bp->ramchain.bundleheight+bp->n )
{
bit = iguana_calcbloom(block->hash2);
if ( iguana_bloomfind(coin,&bp->bloom,0,bit) < 0 )
iguana_bloomset(coin,&bp->bloom,0,bit);
break;
}
}
}
//printf("ht.%d %s %p\n",block->height,bits256_str(str,hash2),hash2p);
bp = 0;
*bundleip = -2;
iguana_blockadd(coin,&bp,bundleip,block);
bp = 0;
*bundleip = -2;
if ( iguana_bundlefind(coin,&bp,bundleip,block->hash2) == 0 )
{
printf("iguana_bundleblockadd A cant find just added.%s bundlei.%d\n",bits256_str(str,hash2),*bundleip);
bp = 0;
*bundleip = -2;
iguana_bundlefind(coin,&bp,bundleip,block->hash2);
break;
}
coin->blocks.hashblocks++;
block = 0;
}
else
{
//printf("break loop block.%p %s coin->blocks.hashblocks %d vs %d\n",block,bits256_str(str,hash2),coin->blocks.hashblocks,coin->blocks.hwmheight);
break;
}
}
}
} else printf("iguana_bundleblockadd returns null\n");
return(retblock);
}*/
int64_t iguana_ramchain_compact(struct iguana_ramchain *ramchain,int32_t numpkinds,int32_t numexternaltxids)
{
int32_t i,diff; int64_t offset; bits256 *src,*dest,tmp;
diff = (ramchain->data->numpkinds - numpkinds);
src = (bits256 *)((long)ramchain->mem->ptr + (long)ramchain->data->Xoffset);
offset = ramchain->data->Poffset + (sizeof(struct iguana_pkhash) * numpkinds);
ramchain->data->Xoffset = offset + ((sizeof(struct iguana_account)+sizeof(struct iguana_pkextra)) * numpkinds);
if ( numpkinds < ramchain->data->numpkinds )
{
ramchain->data->numpkinds = numpkinds;
dest = (bits256 *)((long)ramchain->mem->ptr + (long)offset);
for (i=0; i<numexternaltxids; i++,offset+=sizeof(bits256))
tmp = src[i], dest[i] = tmp; // might be shifting by less than 32 bytes
} else offset += (sizeof(bits256) * numexternaltxids);
ramchain->data->numexternaltxids = numexternaltxids;
ramchain->mem->used = offset;
return(offset);
}
long iguana_blockramchainPT(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_txblock *origtxdata,struct iguana_msgtx *txarray,int32_t txn_count,uint8_t *data,int32_t recvlen)
{
RAMCHAIN_PTRS; struct iguana_ramchain *ramchain = &addr->ramchain;
struct iguana_msgtx *tx; int32_t i,j,err,bundlei = -2; struct iguana_bundle *bp = 0;
if ( iguana_bundlefind(coin,&bp,&bundlei,origtxdata->block.hash2) == 0 )
return(-1);
SETBIT(bp->recv,bundlei);
bp->fpos[bundlei] = -1;
bp->recvlens[bundlei] = recvlen;
if ( iguana_ramchain_init(ramchain,&addr->TXDATA,&addr->HASHMEM,0,txn_count,origtxdata->numunspents,origtxdata->numspends,0,0) == 0 )
return(-1);
iguana_ramchain_link(ramchain,origtxdata->block.hash2,origtxdata->block.hash2,bp->hdrsi,bp->bundleheight+bundlei,1);
_iguana_ramchain_setptrs(ramchain,&T,&U,&U2,&S,&P,&P2,&A,&X);
if ( T == 0 || U == 0 || S == 0 || P == 0 || X == 0 )
{
printf("fatal error getting txdataptrs\n");
return(-1);
}
for (i=0; i<txn_count; i++)
{
tx = &txarray[i];
iguana_ramchain_addtxid(ramchain,T,U,U2,S,P,P2,A,X,tx->txid,tx->tx_out,tx->tx_in);
for (j=0; j<tx->tx_out; j++)
iguana_ramchain_addunspent(ramchain,T,U,U2,S,P,P2,A,X,tx->vouts[j].value,tx->vouts[j].pk_script,tx->vouts[j].pk_scriptlen);
for (j=0; j<tx->tx_in; j++)
iguana_ramchain_addspend(ramchain,T,U,U2,S,P,P2,A,X,tx->vins[j].prev_hash,tx->vins[j].prev_vout,tx->vins[j].script,tx->vins[j].scriptlen,tx->vins[j].sequence);
}
ramchain->data->numpkinds = ramchain->pkind;
ramchain->data->numexternaltxids = ramchain->externalind;
ramchain->data->allocsize = iguana_ramchain_size(ramchain);
if ( (err= iguana_ramchainverify(ramchain)) == 0 )
{
if ( (bp->fpos[bundlei]= iguana_ramchain_save(ramchain,addr->ipbits,bp->hashes[0],bundlei)) >= 0 )
bp->ipbits[bundlei] = addr->ipbits;
} else printf("ramchain verification error.%d hdrsi.%d bundlei.%d\n",err,bp->hdrsi,bundlei);
iguana_ramchain_free(ramchain);
return(bp->fpos[bundlei]);
//iguana_hashfree(addr->txids,0);
//iguana_hashfree(addr->pkhashes,0);
/*txidind = unspentind = spendind = pkind = 0;
for (i=numvouts=numpkinds=0; i<txn_count; i++,txidind++)
{
tx = &txarray[i];
t = &T[txidind];
t->txid = tx->txid, t->txidind = txidind, t->firstvout = unspentind, t->numvouts = tx->tx_out;
iguana_hashsetPT(ramchain,hashmem,'T',t->txid.bytes,txidind);
for (j=0; j<tx->tx_out; j++,numvouts++,unspentind++)
{
u = &U[unspentind];
script = tx->vouts[j].pk_script, scriptlen = tx->vouts[j].pk_scriptlen;
iguana_calcrmd160(coin,rmd160,script,scriptlen,tx->txid);
//char str[65]; init_hexbytes_noT(str,rmd160,20), printf("pkhashes.%p %s %s new pkind.%d pkoffset.%d %d\n",addr->pkhashes,addr->ipaddr,str,numpkinds,txdata->pkoffset,(int32_t)((long)&P[numpkinds] - (long)txdata));
if ( (ptr= iguana_hashfind(ramchain,'P',rmd160)) == 0 )
{
memcpy(P[numpkinds].rmd160,rmd160,sizeof(rmd160));
if ( (ptr= iguana_hashsetPT(ramchain,hashmem,'P',&P[numpkinds],numpkinds)) == 0 )
printf("fatal error adding pkhash\n"), getchar();
//printf("added ptr.%p\n",ptr);
numpkinds++;
} //else printf("found %p[%d] for (%s)\n",ptr,ptr->hh.itemind,str);
u->value = tx->vouts[j].value, u->txidind = txidind;
u->pkind = ptr->hh.itemind;
P[u->pkind].firstunspentind = unspentind;
// prevunspentind requires having accts, so that waits for third pass
}
}
//printf("reallocP.%p -> ",P);
if ( (txdata->numpkinds= numpkinds) > 0 )
P = iguana_memalloc(txmem,sizeof(*P) * numpkinds,0);
//printf("%p\n",P);
externalT = iguana_memalloc(txmem,0,1);
txidind = 0;
for (i=numvins=numexternal=0; i<txn_count; i++,txidind++)
{
tx = &txarray[i];
t = &T[txidind];
t->firstvin = spendind;
for (j=0; j<tx->tx_in; j++)
{
script = tx->vins[j].script, scriptlen = tx->vins[j].scriptlen;
s = &S[spendind];
if ( (sequence= tx->vins[j].sequence) != (uint32_t)-1 )
s->diffsequence = 1;
s->vout = tx->vins[j].prev_vout;
if ( s->vout != 0xffff )
{
if ( (ptr= iguana_hashfind(ramchain,'T',tx->vins[j].prev_hash.bytes)) != 0 )
{
if ( (s->spendtxidind= ptr->hh.itemind) >= txdata->numtxids )
{
s->external = 1;
s->spendtxidind -= txdata->numtxids;
}
}
else
{
s->external = 1;
externalT[numexternal] = tx->vins[j].prev_hash;
iguana_hashsetPT(ramchain,hashmem,'T',externalT[numexternal].bytes,txdata->numtxids + numexternal);
s->spendtxidind = numexternal++;
}
spendind++;
numvins++;
//printf("spendind.%d\n",spendind);
} //else printf("vout.%x\n",s->vout);
// prevspendind requires having accts, so that waits for third pass
}
t->numvins = numvins;
}
if ( (txdata->numexternaltxids= numexternal) > 0 )
externalT = iguana_memalloc(txmem,sizeof(*externalT) * numexternal,0);
txdata->datalen = (int32_t)txmem->used;
txdata->numspends = numvins;
txdata->numpkinds = numpkinds;
txdata->numtxids = txn_count;
//char str[65],buf[9999];
//for (j=buf[0]=0; j<numpkinds; j++)
// init_hexbytes_noT(str,P[j].rmd160,20), sprintf(buf+strlen(buf),"(%d %s) ",j,str);
//printf("%s bundlei.%d T.%d U.%d S.%d P.%d recvlen.%d -> %d\n",buf,bundlei,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,recvlen,txdata->datalen);
if ( numvouts != txdata->numunspents || i != txdata->numtxids )
{
printf("counts mismatch: numvins %d != %d txdata->numvins || numvouts %d != %d txdata->numvouts || i %d != %d txdata->numtxids\n",numvins,txdata->numspends,numvouts,txdata->numunspents,i,txdata->numtxids);
getchar();
exit(-1);
}
else
{
static int32_t maxrecvlen,maxdatalen,maxhashmem; static double recvsum,datasum;
recvsum += recvlen, datasum += txdata->datalen;
if ( recvlen > maxrecvlen )
printf("[%.3f] %.0f/%.0f maxrecvlen %d -> %d\n",recvsum/datasum,recvsum,datasum,maxrecvlen,recvlen), maxrecvlen = recvlen;
if ( txdata->datalen > maxdatalen )
printf("[%.3f] %.0f/%.0f maxdatalen %d -> %d\n",recvsum/datasum,recvsum,datasum,maxdatalen,txdata->datalen), maxdatalen = txdata->datalen;
if ( hashmem != 0 && hashmem->used > maxhashmem )
printf("[%.3f] %.0f/%.0f maxhashmem %d -> %ld\n",recvsum/datasum,recvsum,datasum,maxhashmem,hashmem->used), maxhashmem = (int32_t)hashmem->used;
if ( (rand() % 10000) == 0 )
printf("[%.3f] %.0f/%.0f recvlen vs datalen\n",recvsum/datasum,recvsum,datasum);
if ( origtxdata != 0 )
{
origtxdata->numspends = txdata->numspends;
origtxdata->numpkinds = txdata->numpkinds;
origtxdata->numexternaltxids = txdata->numexternaltxids;
}
}
if ( iguana_peertxsave(coin,&hdrsi,&bundlei,fname,addr,txdata) == txdata )
{
#ifdef __APPLE__
int32_t checki; struct iguana_txblock *checktx; struct iguana_ramchain R,*ptr = &R;
if ( 1 && (checktx= iguana_peertxdata(coin,&checki,fname,txmem,addr->ipbits,txdata->block.hash2)) != 0 && checki == bundlei )
{
if ( iguana_ramchainset(coin,ptr,checktx) == ptr )
{
char str[65]; int32_t j,err;
ptr->txids = ramchain->txids;
ptr->pkhashes = ramchain->pkhashes;
if ( (err= iguana_ramchainverifyPT(coin,ptr)) != 0 )
{
for (j=0; j<ptr->numpkinds; j++)
init_hexbytes_noT(str,ptr->P[j].rmd160,20), printf("[%d %s] ",j,str);
printf("check err.%d ramchain.%s bundlei.%d T.%d U.%d S.%d P.%d\n",err,bits256_str(str,ptr->hash2),bundlei,ptr->numtxids,ptr->numunspents,ptr->numspends,ptr->numpkinds);
}
}
}
#endif
}*/
//printf("free addrtables %p %p\n",addr->txids,addr->pkhashes);
// printf("numpkinds.%d numspends.%d\n",txdata->numpkinds,txdata->numspends);
}
/*void iguana_flushQ(struct iguana_info *coin,struct iguana_peer *addr)
{
struct iguana_helper *ptr;
if ( time(NULL) > addr->lastflush+3 )
{
ptr = mycalloc('i',1,sizeof(*ptr));
ptr->allocsize = sizeof(*ptr);
ptr->coin = coin;
ptr->addr = addr;
ptr->type = 'F';
//printf("FLUSH.%s %u lag.%d\n",addr->ipaddr,addr->lastflush,(int32_t)(time(NULL)-addr->lastflush));
addr->lastflush = (uint32_t)time(NULL);
queue_enqueue("helperQ",&helperQ,&ptr->DL,0);
}
}*/
struct iguana_txblock *iguana_peertxsave(struct iguana_info *coin,int32_t *hdrsip,int32_t *bundleip,char *fname,struct iguana_peer *addr,struct iguana_txblock *txdata)
{
int32_t fpos,bundlei,i,z; FILE *fp;
fpos = 0;
*bundleip = bundlei = iguana_peerfname(coin,hdrsip,fname,addr->ipbits,txdata->block.hash2);
if ( bundlei < 0 || bundlei >= coin->chain->bundlesize )
{
printf(" wont save.(%s) bundlei.%d\n",fname,bundlei);
return(0);
}
txdata->block.hdrsi = *hdrsip;
txdata->block.bundlei = bundlei;
if ( (fp= fopen(fname,"rb+")) == 0 )
{
if ( (fp= fopen(fname,"wb")) != 0 )
{
z = -1;
coin->peers.numfiles++;
for (i=0; i<coin->chain->bundlesize; i++)
fwrite(&z,1,sizeof(z),fp);
fclose(fp);
fp = fopen(fname,"rb+");
}
}
if ( fp != 0 )
{
fseek(fp,0,SEEK_END);
fpos = (int32_t)ftell(fp);
//printf("%s fpos.%d: bundlei.%d datalen.%d\n",fname,fpos,bundlei,txdata->datalen);
fwrite(&bundlei,1,sizeof(bundlei),fp);
fwrite(&txdata->block.hash2,1,sizeof(txdata->block.hash2),fp);
fwrite(&txdata->datalen,1,sizeof(txdata->datalen),fp);
fwrite(txdata,1,txdata->datalen,fp);
fseek(fp,bundlei * sizeof(bundlei),SEEK_SET);
//printf("bundlei[%d] <- fpos.%d\n",bundlei,fpos);
fwrite(&fpos,1,sizeof(fpos),fp);
fclose(fp);
//for (i=0; i<txdata->numpkinds; i++)
// printf("%016lx ",*(long *)((struct iguana_pkhash *)((long)txdata + txdata->pkoffset))[i].rmd160);
//printf("create.(%s) %d ",fname,bundlei,coin->peers.numfiles);
//printf("bundlei.%d datalen.%d T.%d U.%d S.%d P.%d X.%d\n",bundlei,txdata->datalen,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,txdata->numexternaltxids);
return(txdata);
}
return(0);
}
struct iguana_txblock *iguana_peertxdata(struct iguana_info *coin,int32_t *bundleip,char *fname,struct iguana_memspace *mem,uint32_t ipbits,bits256 hash2)
{
int32_t bundlei,datalen,checki,hdrsi,fpos; char str[65],str2[65]; FILE *fp;
bits256 checkhash2; struct iguana_txblock *txdata = 0;
if ( (bundlei= iguana_peerfname(coin,&hdrsi,fname,ipbits,hash2)) >= 0 )
{
if ( (fp= fopen(fname,"rb")) != 0 )
{
fseek(fp,bundlei * sizeof(bundlei),SEEK_SET);
fread(&fpos,1,sizeof(fpos),fp);
fseek(fp,fpos,SEEK_SET);
fread(&checki,1,sizeof(checki),fp);
if ( ftell(fp)-sizeof(checki) == fpos && bundlei == checki )
{
fread(&checkhash2,1,sizeof(checkhash2),fp);
if ( memcmp(hash2.bytes,checkhash2.bytes,sizeof(hash2)) == 0 )
{
fread(&datalen,1,sizeof(datalen),fp);
if ( datalen < (mem->totalsize - mem->used - 4) )
{
if ( (txdata= iguana_memalloc(mem,datalen,0)) != 0 )
{
fread(txdata,1,datalen,fp);
if ( txdata->datalen != datalen || txdata->block.bundlei != bundlei )
{
printf("%s peertxdata txdata->datalen.%d != %d bundlei.%d vs %d\n",bits256_str(str,txdata->block.hash2),txdata->datalen,datalen,txdata->block.bundlei,bundlei);
getchar();
txdata = 0;
iguana_memreset(mem);
} //else printf("SUCCESS txdata.%s bundlei.%d fpos.%d T.%d U.%d S.%d P.%d\n",bits256_str(str,txdata->block.hash2),bundlei,fpos,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds);
} else printf("peertxdata error allocating txdata\n");
} else printf("mismatch peertxdata datalen %d vs %ld totalsize %ld\n",datalen,mem->totalsize - mem->used - 4,(long)mem->totalsize);
} else printf("peertxdata hash mismatch %s != %s\n",bits256_str(str,hash2),bits256_str(str2,checkhash2));
} else printf("peertxdata bundlei.%d != checki.%d, fpos.%d ftell.%ld\n",bundlei,checki,fpos,ftell(fp));
fclose(fp);
} else printf("cant find file.(%s)\n",fname);
} //else printf("bundlei.%d\n",bundlei);
*bundleip = bundlei;
return(txdata);
}
/*if ( (n= ramchain->data->numtxids) > 0 )
{
for (ramchain->txidind=ramchain->data->firsti; ramchain->txidind<n; ramchain->txidind++)
{
tx = &T[ramchain->txidind];
//printf("tx.%p (%d) %d txidind.%d\n",tx,(int32_t)((long)tx - (long)ramchain->mem->ptr),(int32_t)ramchain->mem->totalsize,ramchain->txidind);
iguana_ramchain_addtxid(coin,RAMCHAIN_ARG,tx->txid,tx->numvouts,tx->numvins);
//if ( (ptr= iguana_hashsetPT(ramchain,'T',&tx->txid.bytes,ramchain->txidind)) != 0 )
{
for (j=0; j<tx->numvouts; j++)
{
iguana_ramchain_addunspent(coin,RAMCHAIN_ARG,U[ramchain->unspentind].value,P[U[ramchain->unspentind].pkind].rmd160,-20,tx->txid,j);
}
}
ramchain->spendind += tx->numvins;
}
ramchain->externalind = ramchain->data->numexternaltxids;
}
if ( (err= iguana_ramchainverify(coin,ramchain)) != 0 )
{
printf("iguana_ramchain_map.(%s) err.%d verifying ramchain\n",fname,err);
iguana_ramchain_free(ramchain,hashmem == 0);
munmap(ptr,filesize);
}*/
//printf("mapped ramchain verified\n");
#define iguana_hashfind(hashtable,key,keylen) iguana_hashsetHT(hashtable,0,key,keylen,-1)
struct iguana_kvitem *iguana_hashsetHT(struct iguana_kvitem *hashtable,struct iguana_memspace *mem,void *key,int32_t keylen,int32_t itemind)
{
struct iguana_kvitem *ptr = 0; int32_t allocsize;
HASH_FIND(hh,hashtable,key,keylen,ptr);
if ( ptr == 0 && itemind >= 0 )
{
allocsize = (int32_t)(sizeof(*ptr));
if ( mem != 0 )
ptr = iguana_memalloc(mem,allocsize,1);
else ptr = mycalloc('t',1,allocsize);
if ( ptr == 0 )
printf("fatal alloc error in hashset\n"), exit(-1);
//printf("ptr.%p allocsize.%d key.%p keylen.%d itemind.%d\n",ptr,allocsize,key,keylen,itemind);
ptr->hh.itemind = itemind;
HASH_ADD_KEYPTR(hh,hashtable,key,keylen,ptr);
}
if ( ptr != 0 )
{
struct iguana_kvitem *tmp;
HASH_FIND(hh,hashtable,key,keylen,tmp);
char str[65];
init_hexbytes_noT(str,key,keylen);
if ( tmp != ptr )
printf("%s itemind.%d search error %p != %p\n",str,itemind,ptr,tmp);
// else printf("added.(%s) height.%d %p\n",str,itemind,ptr);
}
return(ptr);
}
int32_t iguana_parseblock(struct iguana_info *coin,struct iguana_block *block,struct iguana_msgtx *tx,int32_t numtx)
{
#ifdef oldway
int32_t txind,pkind,i; uint16_t numvouts,numvins;
pkind = block->L.numpkinds = coin->latest.dep.numpkinds;
block->L.supply = coin->latest.dep.supply;
if ( block->L.numtxids != coin->latest.dep.numtxids || block->L.numunspents != coin->latest.dep.numunspents || block->L.numspends != coin->latest.dep.numspends || block->L.numpkinds != coin->latest.dep.numpkinds )
{
printf("Block.(h%d t%d u%d s%d p%d) vs coin.(h%d t%d u%d s%d p%d)\n",block->height,block->L.numtxids,block->L.numunspents,block->L.numspends,block->L.numpkinds,coin->blocks.parsedblocks,coin->latest.dep.numtxids,coin->latest.dep.numunspents,coin->latest.dep.numspends,coin->latest.dep.numpkinds);
block->L.numtxids = coin->latest.dep.numtxids;
block->L.numunspents = coin->latest.dep.numunspents;
block->L.numspends = coin->latest.dep.numspends;
block->L.numpkinds = coin->latest.dep.numpkinds;
iguana_kvwrite(coin,coin->blocks.db,0,block,(uint32_t *)&block->height);
//getchar();
}
vcalc_sha256(0,coin->latest.ledgerhash.bytes,coin->latest.lhashes[0].bytes,sizeof(coin->latest.lhashes));
coin->LEDGER.snapshot.dep = block->L;
memcpy(&coin->LEDGER.snapshot.ledgerhash,&coin->latest.ledgerhash,sizeof(coin->latest.ledgerhash));
memcpy(coin->LEDGER.snapshot.lhashes,coin->latest.lhashes,sizeof(coin->latest.lhashes));
memcpy(coin->LEDGER.snapshot.states,coin->latest.states,sizeof(coin->latest.states));
//printf("%08x Block.(h%d t%d u%d s%d p%d) vs (h%d t%d u%d s%d p%d)\n",(uint32_t)coin->latest.ledgerhash.txid,block->height,block->L.numtxids,block->L.numunspents,block->L.numspends,block->L.numpkinds,coin->blocks.parsedblocks,coin->latest.dep.numtxids,coin->latest.dep.numunspents,coin->latest.dep.numspends,coin->latest.dep.numpkinds);
if ( (coin->blocks.parsedblocks % 1000) == 0 )
{
for (i=0; i<IGUANA_NUMAPPENDS; i++)
printf("%llx ",(long long)coin->LEDGER.snapshot.lhashes[i].txid);
char str[65];
bits256_str(str,coin->LEDGER.snapshot.ledgerhash);
printf("-> pre parse %s ledgerhashes.%d\n",str,coin->blocks.parsedblocks);
}
coin->LEDGER.snapshot.blockhash = block->hash2;
coin->LEDGER.snapshot.merkle_root = block->merkle_root;
coin->LEDGER.snapshot.timestamp = block->timestamp;
coin->LEDGER.snapshot.credits = coin->latest.credits;
coin->LEDGER.snapshot.debits = coin->latest.debits;
coin->LEDGER.snapshot.height = block->height;
//if ( coin->blocks.parsedblocks > 0 && (coin->blocks.parsedblocks % coin->chain->bundlesize) == 0 )
// coin->R.bundles[coin->blocks.parsedblocks / coin->chain->bundlesize].presnapshot = coin->LEDGER.snapshot;
for (txind=block->numvouts=block->numvins=0; txind<block->txn_count; txind++)
{
//printf("block.%d txind.%d numvouts.%d numvins.%d block->(%d %d) U%d coin.%d\n",block->height,txind,numvouts,numvins,block->numvouts,block->numvins,block->L.numunspents,coin->latest.dep.numunspents);
//fprintf(stderr,"t");
if ( ramchain_parsetx(coin,&coin->mining,&coin->totalfees,&numvouts,&numvins,block->height,txind,&tx[txind],block->L.numtxids+txind,block->L.numunspents + block->numvouts,block->L.numspends + block->numvins) < 0 )
return(-1);
block->numvouts += numvouts;
block->numvins += numvins;
//printf("block.%d txind.%d numvouts.%d numvins.%d block->(%d %d) 1st.(%d %d)\n",block->height,txind,numvouts,numvins,block->numvouts,block->numvins,block->L.numunspents,block->L.numspends);
}
//printf(" Block.(h%d t%d u%d s%d p%d) vs coin.(h%d t%d u%d s%d p%d)\n",block->height,block->L.numtxids,block->L.numunspents,block->L.numspends,block->L.numpkinds,coin->blocks.parsedblocks,coin->latest.dep.numtxids,coin->latest.dep.numunspents,coin->latest.dep.numspends,coin->latest.dep.numpkinds);
if ( coin->latest.dep.supply != (coin->latest.credits - coin->latest.debits) )
{
printf("height.%d supply %.8f != %.8f (%.8f - %.8f)\n",block->height,dstr(coin->latest.dep.supply),dstr(coin->latest.credits)-dstr(coin->latest.debits),dstr(coin->latest.credits),dstr(coin->latest.debits));
getchar();
}
#ifdef IGUANA_VERIFYFLAG
while ( pkind < coin->latest.dep.numpkinds )
{
int64_t err;
if ( (err= iguana_verifyaccount(coin,&coin->accounts[pkind],pkind)) < 0 )
printf("pkind.%d err.%lld %.8f last.(U%d S%d)\n",pkind,(long long)err,dstr(coin->accounts[pkind].balance),coin->accounts[pkind].lastunspentind,coin->accounts[pkind].lastspendind), getchar();
pkind++;
}
#endif
coin->parsetime = (uint32_t)time(NULL);
coin->parsemillis = milliseconds();
iguana_kvwrite(coin,coin->blocks.db,0,block,(uint32_t *)&block->height);
if ( (coin->blocks.parsedblocks > coin->longestchain-100000 && (coin->blocks.parsedblocks % 100) == 0) || (coin->blocks.parsedblocks > coin->longestchain-1000 && (coin->blocks.parsedblocks % 10) == 0) || coin->blocks.parsedblocks > coin->longestchain-100 || (coin->blocks.parsedblocks % 100) == 0 )
{
printf("PARSED.%d T.%d U.%d+%d S.%d+%d P.%d hwm.%d longest.%d | %.8f - %.8f %.8f [%.8f] M %.8f F %.8f | %.02f minutes %.2f%% %.2f%% %.2f%% avail\n",coin->blocks.parsedblocks,coin->latest.dep.numtxids,block->L.numunspents,block->numvouts,block->L.numspends,block->numvins,block->L.numpkinds,coin->blocks.hwmheight,coin->longestchain,dstr(coin->latest.credits),dstr(coin->latest.debits),dstr(coin->latest.credits)-dstr(coin->latest.debits),(dstr(coin->latest.credits)-dstr(coin->latest.debits))/coin->blocks.parsedblocks,dstr(coin->mining),dstr(coin->totalfees),((double)time(NULL)-coin->starttime)/60.,(double)iguana_avail(coin,coin->blocks.parsedblocks+1,1000)/10.,(double)iguana_avail(coin,coin->blocks.parsedblocks+1,25000)/250.,100.*(double)iguana_avail(coin,coin->blocks.parsedblocks+1,coin->longestchain-coin->blocks.parsedblocks-1)/(coin->longestchain-coin->blocks.parsedblocks));
myallocated(0,0);
}
if ( 0 && coin->loadedLEDGER.snapshot.height == coin->blocks.parsedblocks )
{
memcpy(&coin->latest.ledgerhash,&coin->loadedLEDGER.snapshot.ledgerhash,sizeof(coin->loadedLEDGER.snapshot.ledgerhash));
memcpy(coin->latest.lhashes,coin->loadedLEDGER.snapshot.lhashes,sizeof(coin->loadedLEDGER.snapshot.lhashes));
printf("restore lhashes, special alignement case\n");
} //else printf("loaded.%d vs parsed.%d\n",coin->loadedLEDGER.snapshot.height,coin->blocks.parsedblocks);
coin->blocks.parsedblocks++;
#endif
return(0);
}
int32_t iguana_updateramchain(struct iguana_info *coin)
{
return(0);
}
int32_t iguana_hashfree(struct iguana_kvitem *hashtable,int32_t delitem)
{
struct iguana_kvitem *item,*tmp; int32_t n = 0;
if ( hashtable != 0 )
{
HASH_ITER(hh,hashtable,item,tmp)
{
//printf("hashdelete.%p allocsize.%d itemind.%d delitem.%d\n",item,item->allocsize,item->hh.itemind,delitem);
if ( delitem != 0 )
{
HASH_DEL(hashtable,item);
//if ( delitem > 1 )
// myfree(item,item->allocsize);
}
n++;
}
}
return(n);
}
struct iguana_txblock *iguana_ramchainptrs(struct iguana_txid **Tptrp,struct iguana_unspent20 **Uptrp,struct iguana_spend256 **Sptrp,struct iguana_pkhash **Pptrp,bits256 **externalTptrp,struct iguana_memspace *mem,struct iguana_txblock *origtxdata)
{
char str[65]; struct iguana_txblock *txdata; int32_t allocsize,extralen,rwflag = (origtxdata != 0);
iguana_memreset(mem);
allocsize = (int32_t)(sizeof(*txdata) - sizeof(txdata->space) + ((origtxdata != 0) ? origtxdata->extralen : 0));
mem->alignflag = sizeof(uint32_t);
if ( (txdata= iguana_memalloc(mem,allocsize,0)) == 0 )
return(0);
//printf("ptr.%p alloctxdata.%p T.%d U.%d S.%d P.%d\n",mem->ptr,txdata,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds);
extralen = (origtxdata != 0) ? origtxdata->extralen : txdata->extralen;
if ( origtxdata != 0 )
{
//printf("copy %d bytes from %p to %p extralen.%d size.%ld T.%d U.%d S.%d P.%d \n",allocsize,origtxdata,txdata,extralen,sizeof(*txdata),txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds);
memcpy(txdata,origtxdata,allocsize);
} else iguana_memalloc(mem,txdata->extralen,0);
*Tptrp = iguana_memalloc(mem,sizeof(**Tptrp) * txdata->numtxids,rwflag);
*Uptrp = iguana_memalloc(mem,sizeof(**Uptrp) * txdata->numunspents,rwflag);
*Sptrp = iguana_memalloc(mem,sizeof(**Sptrp) * txdata->numspends,rwflag);
//printf("rwflag.%d ptr.%p alloctxdata.%p T.%d U.%d S.%d P.%d pkoffset.%ld X.%d\n",rwflag,mem->ptr,txdata,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,mem->used,txdata->numexternaltxids);
if ( externalTptrp != 0 )
{
if ( txdata->pkoffset < (int32_t)mem->used )
printf("allocsize.%d size.%ld %p %s (T.%d U.%d S.%d P.%d X.%d) iguana_ramchainptrs pkoffset.%d != %ld numspends.%d\n",allocsize,sizeof(*txdata),txdata,bits256_str(str,txdata->block.hash2),txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,txdata->numexternaltxids,txdata->pkoffset,mem->used,txdata->numspends), getchar();
mem->used = txdata->pkoffset;
*Pptrp = iguana_memalloc(mem,sizeof(**Pptrp) * txdata->numpkinds,rwflag);
*externalTptrp = iguana_memalloc(mem,txdata->numexternaltxids * sizeof(**externalTptrp),rwflag);
}
else
{
txdata->pkoffset = (int32_t)mem->used;
// printf("set pkoffset.%d\n",txdata->pkoffset);
*Pptrp = iguana_memalloc(mem,0,rwflag);
}
if ( 0 && rwflag == 0 )
printf("datalen.%d rwflag.%d origtxdat.%p allocsize.%d extralen.%d T.%d U.%d S.%d P.%d X.%p[%d]\n",(int32_t)mem->totalsize,rwflag,origtxdata,allocsize,extralen,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,externalTptrp!=0?*externalTptrp:0,txdata->numexternaltxids);
return(txdata);
}
int32_t iguana_ramchainsave(struct iguana_info *coin,struct iguana_ramchain *ramchain)
{
FILE *fp; char fname[1024],str[65];
sprintf(fname,"DB/%s/%s.%d",coin->symbol,bits256_str(str,ramchain->H.data->firsthash2),ramchain->H.hdrsi);
if ( (fp= fopen(fname,"wb")) != 0 )
{
fwrite(ramchain,1,ramchain->H.data->allocsize,fp);
fclose(fp);
}
printf("ramchainsave.%s %d[%d] %s\n",coin->symbol,ramchain->H.hdrsi,ramchain->numblocks,mbstr(str,ramchain->H.data->allocsize));
return(0);
}
int32_t iguana_ramchainfree(struct iguana_info *coin,struct iguana_memspace *mem,struct iguana_ramchain *ramchain)
{
if ( ramchain->txids != 0 )
iguana_hashfree(ramchain->txids,1);
if ( ramchain->pkhashes != 0 )
iguana_hashfree(ramchain->pkhashes,1);
iguana_mempurge(mem);
return(0);
}
/*struct iguana_ramchain *iguana_ramchainset(struct iguana_info *coin,struct iguana_ramchain *ramchain,struct iguana_txblock *txdata)
{
struct iguana_memspace txmem;
memset(&txmem,0,sizeof(txmem));
iguana_meminit(&txmem,"bramchain",txdata,txdata->datalen,0);
//printf("ramchainset <- txdata.%p memptr.%p T.%d U.%d S.%d P.%d X.%d\n",txdata,txmem.ptr,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,txdata->numexternaltxids);
if ( iguana_ramchainptrs(&ramchain->T,&ramchain->U,&ramchain->S,&ramchain->P,&ramchain->externalT,&txmem,0) != txdata || ramchain->T == 0 || ramchain->U == 0 || ramchain->S == 0 || ramchain->P == 0 )
{
printf("iguana_ramchainset: cant set pointers txdata.%p\n",txdata);
return(0);
}
//int32_t i;
// for (i=0; i<344; i++)
// printf("%02x ",((uint8_t *)txdata)[i]);
//for (i=-1; i<2; i++)
// printf("%016lx ",*(long *)((struct iguana_pkhash *)((long)txdata + txdata->pkoffset))[i].rmd160);
//printf("datalen.%d T.%d U.%d S.%d P.%d X.%d | %d vs %d ramchain.%p txdata.%p\n",txdata->datalen,txdata->numtxids,txdata->numunspents,txdata->numspends,txdata->numpkinds,txdata->numexternaltxids,txdata->pkoffset,(int32_t)((long)ramchain->P - (long)txdata),ramchain,txdata);
ramchain->numtxids = txdata->numtxids;
ramchain->numunspents = txdata->numunspents;
ramchain->numspends = txdata->numspends;
ramchain->numpkinds = txdata->numpkinds;
ramchain->numexternaltxids = txdata->numexternaltxids;
//printf("ramchain T.%d U.%d S.%d P.%d X.%d %p\n",ramchain->numtxids,ramchain->numunspents,ramchain->numspends,ramchain->numpkinds,ramchain->numexternaltxids,ramchain->externalT);
if ( ramchain->numexternaltxids != 0 && ramchain->externalT == 0 )
getchar();
ramchain->prevhash2 = txdata->block.prev_block;
ramchain->hash2 = txdata->block.hash2;
return(ramchain);
}
int32_t iguana_ramchaintxid(struct iguana_info *coin,bits256 *txidp,struct iguana_ramchain *ramchain,struct iguana_spend *s)
{
memset(txidp,0,sizeof(*txidp));
//printf("s.%p ramchaintxid vout.%x spendtxidind.%d numexternals.%d isext.%d numspendinds.%d\n",s,s->vout,s->spendtxidind,ramchain->numexternaltxids,s->external,ramchain->numspends);
if ( s->vout == 0xffff )
return(0);
if ( s->external != 0 && s->spendtxidind < ramchain->numexternaltxids )
{
*txidp = ramchain->externalT[s->spendtxidind];
return(0);
}
else if ( s->external == 0 && s->spendtxidind < ramchain->numtxids )
{
*txidp = ramchain->T[s->spendtxidind].txid;
return(0);
}
return(-1);
}*/
/*if ( ptr->type == 'F' )
{
if ( addr != 0 && addr->fp != 0 )
{
//printf("flush.%s %p\n",addr->ipaddr,addr->fp);
fflush(addr->fp);
}
}
else*/
/* struct iguana_txblock *ptr; struct iguana_ramchain *ptrs[IGUANA_MAXBUNDLESIZE],*ramchains;
struct iguana_block *block; char fname[1024]; uint64_t estimatedsize = 0;
int32_t i,maxrecv,addrind,flag,bundlei,numdirs=0; struct iguana_ramchain *ramchain;
flag = maxrecv = 0;
memset(ptrs,0,sizeof(ptrs));
ramchains = mycalloc('p',coin->chain->bundlesize,sizeof(*ramchains));
for (i=0; i<bp->n && i<coin->chain->bundlesize; i++)
{
if ( (block= iguana_blockfind(coin,bp->hashes[i])) != 0 )
{
iguana_meminit(&memB[i],"ramchainB",0,block->recvlen*2 + 8192,0);
if ( (ptr= iguana_peertxdata(coin,&bundlei,fname,&memB[i],block->ipbits,block->hash2)) != 0 )
{
if ( bundlei != i || ptr->block.bundlei != i )
printf("peertxdata.%d bundlei.%d, i.%d block->bundlei.%d\n",bp->hdrsi,bundlei,i,ptr->block.bundlei);
ptrs[i] = &ramchains[i];
//char str[65];
//printf("received txdata.%s bundlei.%d T.%d U.%d S.%d P.%d\n",bits256_str(str,ptr->block.hash2),bundlei,ptr->numtxids,ptr->numunspents,ptr->numspends,ptr->numpkinds);
if ( iguana_ramchainset(coin,ptrs[i],ptr) == ptrs[i] )
{
char str[65]; int32_t err;
//for (j=0; j<ptrs[i]->numpkinds; j++)
// init_hexbytes_noT(str,ptrs[i]->P[j].rmd160,20), printf("%s ",str);
err = iguana_ramchainverifyPT(coin,ptrs[i]);
printf("conv err.%d ramchain.%s bundlei.%d T.%d U.%d S.%d P.%d\n",err,bits256_str(str,ptrs[i]->data->firsthash2),bundlei,ptrs[i]->data->numtxids,ptrs[i]->data->numunspents,ptrs[i]->data->numspends,ptrs[i]->data->numpkinds);
ptrs[i]->data->firsti = 0;
if ( block->recvlen > maxrecv )
maxrecv = block->recvlen;
estimatedsize += block->recvlen;
flag++;
} else printf("error setting ramchain.%d\n",i);
}
else
{
printf("error (%s) hdrs.%d ptr[%d]\n",fname,bp->hdrsi,i);
CLEARBIT(bp->recv,i);
bp->issued[i] = 0;
block = 0;
}
}
}
if ( flag == i )
{
printf("numpkinds >>>>>>>>> start MERGE.(%ld) i.%d flag.%d estimated.%ld maxrecv.%d\n",(long)mem->totalsize,i,flag,(long)estimatedsize,maxrecv);
if ( (ramchain= iguana_ramchainmergeHT(coin,mem,ptrs,i,bp)) != 0 )
{
iguana_ramchainsave(coin,ramchain);
iguana_ramchainfree(coin,mem,ramchain);
//printf("ramchain saved\n");
bp->emitfinish = (uint32_t)time(NULL);
for (addrind=0; addrind<IGUANA_MAXPEERS; addrind++)
{
if ( coin->peers.active[addrind].ipbits != 0 )
{
if ( iguana_peerfile_exists(coin,&coin->peers.active[addrind],fname,bp->hashes[0]) >= 0 )
{
//printf("remove.(%s)\n",fname);
//iguana_removefile(fname,0);
//coin->peers.numfiles--;
}
}
}
} else bp->emitfinish = 0;
}
else
{
printf(">>>>> bundlesaveHT error: numdirs.%d i.%d flag.%d\n",numdirs,i,flag);
bp->emitfinish = 0;
}
for (i=0; i<bp->n && i<coin->chain->bundlesize; i++)
iguana_mempurge(&memB[i]);
myfree(ramchains,coin->chain->bundlesize * sizeof(*ramchains));
return(flag);*/
#ifdef oldway
int32_t iguana_verifyiAddr(struct iguana_info *coin,void *key,void *value,int32_t itemind,int32_t itemsize)
{
struct iguana_iAddr *iA = value;
if ( itemind == 0 || iA->ipbits != 0 )
return(0);
else return(-1);
}
int32_t iguana_initiAddr(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,int32_t itemind,int32_t itemsize,int32_t numitems)
{
struct iguana_iAddr *iA = value;
if ( key == 0 && value == 0 && itemind < 0 && numitems == 0 )
{
}
else
{
if ( iA != 0 )
iA->status = 0;
coin->numiAddrs++;
//printf("%x numiAddrs.%d\n",iA->ipbits,coin->numiAddrs);
}
return(0);
}
int32_t iguana_verifyblock(struct iguana_info *coin,void *key,void *value,int32_t itemind,int32_t itemsize)
{
struct iguana_block *block;
block = value;
if ( bits256_nonz(block->hash2) != 0 )
return(0);
else return(-1);
}
int32_t iguana_initblock(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,int32_t itemind,int32_t itemsize,int32_t numitems)
{
bits256 genesis; //struct iguana_block *block = value;
if ( key == 0 && value == 0 && itemind < 0 && numitems == 0 )
{
if ( coin->blocks.db == 0 )
coin->blocks.db = kv;
genesis = iguana_genesis(coin,coin->chain);
if ( bits256_nonz(genesis) == 0 )
return(-1);
else return(0);
}
return(0);
}
int32_t iguana_nullinit(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,int32_t itemind,int32_t itemsize,int32_t numitems)
{
if ( key != 0 && value != 0 && itemind > 0 )
{
}
return(0);
}
int32_t iguana_verifyunspent(struct iguana_info *coin,void *key,void *value,int32_t itemind,int32_t itemsize)
{
if ( itemind < coin->latest.dep.numunspents )
return(0);
else return(-1);
}
int32_t iguana_verifyspend(struct iguana_info *coin,void *key,void *value,int32_t itemind,int32_t itemsize)
{
if ( itemind < coin->latest.dep.numspends )
return(0);
else return(-1);
}
int32_t iguana_verifytxid(struct iguana_info *coin,void *key,void *value,int32_t itemind,int32_t itemsize)
{
if ( itemind < coin->latest.dep.numtxids )
return(0);
else return(-1);
}
int32_t iguana_inittxid(struct iguana_info *coin,struct iguanakv *kv,void *key,void *value,int32_t itemind,int32_t itemsize,int32_t numitems)
{
//uint32_t checktxidind,firstvout,firstvin; struct iguana_txid *tx = value;
if ( key != 0 && value != 0 && itemind > 0 )
{
/*printf("inittxid.(%s) itemind.%d (%d %d)\n",bits256_str(tx->txid),itemind,tx->firstvout,tx->firstvin);
checktxidind = iguana_txidind(coin,&firstvout,&firstvin,tx->txid);
if ( checktxidind != itemind )
{
printf("init checktxidind != itemind: %s -> %d vs %d\n",bits256_str(tx->txid),checktxidind,itemind);
return(-1);
}*/
}
return(0);
}
int32_t iguana_verifypkhash(struct iguana_info *coin,void *key,void *value,int32_t itemind,int32_t itemsize)
{
if ( itemind < coin->latest.dep.numpkinds )
return(0);
else return(-1);
}
struct iguanakv *iguana_kvinit(char *name,int32_t keysize,int32_t threadsafe,int32_t mapped_datasize,int32_t RAMvaluesize,int32_t keyoffset,int32_t flags,int32_t valuesize2,int32_t valuesize3)
{
struct iguanakv *kv;
printf("iguana_kvinit.(%s) keysize.%d mapped_datasize.%d keyoffset.%d\n",name,keysize,mapped_datasize,keyoffset);
kv = mycalloc('K',1,sizeof(*kv));
portable_mutex_init(&kv->MMlock);
//portable_mutex_init(&kv->MEM.mutex);
portable_mutex_init(&kv->HASHPTRS.mutex);
portable_mutex_init(&kv->KVmutex);
strcpy(kv->name,name);
kv->flags = flags;
kv->valuesize2 = valuesize2, kv->valuesize3 = valuesize3;
kv->RAMvaluesize = RAMvaluesize;
kv->HDDvaluesize = mapped_datasize;
kv->keyoffset = keyoffset;
kv->mult = IGUANA_ALLOC_MULT;
kv->threadsafe = threadsafe;
kv->keysize = keysize;
return(kv);
}
int32_t iguana_loadkvfile(struct iguana_info *coin,struct iguanakv *kv,int32_t valuesize,int32_t (*verifyitem)(struct iguana_info *coin,void *key,void *ptr,int32_t itemind,int32_t itemsize),int32_t (*inititem)(struct iguana_info *coin,struct iguanakv *kv,void *key,void *ptr,int32_t itemind,int32_t itemsize,int32_t numitems),int32_t maxind)
{
FILE *fp; long fpos; uint8_t *ptr; double lastdisp,factor; int32_t numitems=0,itemind,j,n,skip = 0;
factor = 1.;
if ( (fp= fopen(kv->fname,"rb")) != 0 )
{
fseek(fp,0,SEEK_END);
fpos = ftell(fp);
numitems = (int32_t)(fpos / valuesize);
fclose(fp);
if ( kv->RAMvaluesize > 0 && kv->HDDvaluesize > 0 && kv->RAMvaluesize > kv->HDDvaluesize && numitems > 0 )
numitems--;
iguana_kvensure(coin,kv,0);
if ( numitems > 2 || maxind > 0 )
{
if ( maxind == 0 )
{
for (itemind=numitems-2; itemind>0; itemind--)
{
ptr = (uint8_t *)((unsigned long)kv->M.fileptr + ((unsigned long)itemind * kv->HDDvaluesize));
if ( (*verifyitem)(coin,(void *)&ptr[kv->keyoffset],(void *)ptr,itemind,kv->RAMvaluesize) < 0 )
{
numitems = itemind + 1;
printf("numitems.%d\n",numitems);
break;
}
}
} else numitems = maxind;
if ( numitems > 0 )
{
lastdisp = 0.;
for (itemind=0; itemind<numitems; itemind++)
{
if ( numitems > 1000000 && ((double)itemind / numitems) > lastdisp+.01*factor )
{
if ( factor == 1. )
fprintf(stderr,"%.0f%% ",100. * lastdisp);
else fprintf(stderr,"%.2f%% ",100. * lastdisp);
lastdisp = ((double)itemind / numitems);
}
ptr = (uint8_t *)((uint64_t)kv->M.fileptr + ((uint64_t)itemind * kv->HDDvaluesize));
if ( 0 && kv->keysize > 0 )
{
for (j=0; j<kv->keysize; j++)
if ( ptr[j] != 0 )
break;
if ( j != kv->keysize && iguana_kvread(coin,kv,(void *)&ptr[kv->keyoffset],kv->space,(uint32_t *)&n) != 0 )
{
printf("%s: skip duplicate %llx itemind.%d already at %d\n",kv->name,*(long long *)&ptr[kv->keyoffset],itemind,n);
continue;
}
//printf("%s uniq item at itemind.%d\n",kv->name,itemind);
}
if ( (*verifyitem)(coin,(void *)&ptr[kv->keyoffset],(void *)ptr,itemind,kv->RAMvaluesize) == 0 )
{
//if ( strcmp("txids",kv->name) == 0 )
//printf("inititem.%d %p (%s)\n",itemind,ptr,bits256_str(*(bits256 *)&ptr[kv->keyoffset]));
// iguana_kvwrite(coin,kv,(void *)&ptr[kv->keyoffset],sp->space,(uint32_t *)&n);
if ( (*inititem)(coin,kv,(void *)&ptr[kv->keyoffset],(void *)ptr,itemind,kv->RAMvaluesize,numitems) == 0 )
{
kv->numvalid++;
n = itemind;
memcpy(kv->space,ptr,kv->RAMvaluesize);
if ( kv->keysize > 0 )
iguana_kvwrite(coin,kv,(void *)&ptr[kv->keyoffset],kv->space,(uint32_t *)&n);
else iguana_kvwrite(coin,kv,0,kv->space,(uint32_t *)&n);
} else skip++;
} else break;
}
}
}
kv->numitems = numitems;
kv->numkeys = numitems;
kv->maxitemind = (numitems > 0 ) ? numitems - 1 : 0;
printf("%s: numkeys.%d numitems.%d numvalid.%d maxitemind.%d skipped.%d ELAPSED %.2f minutes\n",kv->name,kv->numkeys,kv->numitems,kv->numvalid,kv->maxitemind,skip,(double)(time(NULL)-coin->starttime)/60.);
if ( (kv->flags & IGUANA_ITEMIND_DATA) != 0 )
iguana_syncmap(&kv->M,0);
/*if ( strcmp(kv->name,"iAddrs") == 0 && kv->numkeys < numitems/2 )
{
iguana_closemap(&kv->M);
printf("truncate?\n"), getchar();
truncate(kv->fname,(kv->numkeys+100)*kv->HDDvaluesize);
}*/
}
return(numitems);
}
struct iguanakv *iguana_stateinit(struct iguana_info *coin,int32_t flags,char *coinstr,char *subdir,char *name,int32_t keyoffset,int32_t keysize,int32_t HDDvaluesize,int32_t RAMvaluesize,int32_t inititems,int32_t (*verifyitem)(struct iguana_info *coin,void *key,void *ptr,int32_t itemind,int32_t itemsize),int32_t (*inititem)(struct iguana_info *coin,struct iguanakv *kv,void *key,void *ptr,int32_t itemind,int32_t itemsize,int32_t numitems),int32_t valuesize2,int32_t valuesize3,int32_t maxind,int32_t initialnumitems,int32_t threadsafe)
{
struct iguanakv *kv; int32_t valuesize;
if ( maxind <= 1 )
maxind = 0;
printf("%s MAX.%d\n",name,maxind);
if ( HDDvaluesize == 0 )
valuesize = HDDvaluesize = RAMvaluesize;
else valuesize = HDDvaluesize;
kv = iguana_kvinit(name,keysize,threadsafe,HDDvaluesize,RAMvaluesize,keyoffset,flags,valuesize2,valuesize3);
if ( kv == 0 )
{
printf("cant initialize kv.(%s)\n",name);
exit(-1);
}
if ( (kv->incr= inititems) == 0 )
kv->incr = IGUANA_ALLOC_INCR;
strcpy(kv->name,name);
sprintf(kv->fname,"DB/%s/%s",coin->symbol,kv->name), iguana_compatible_path(kv->fname);
portable_mutex_init(&kv->MMmutex);
kv->space = mycalloc('K',1,RAMvaluesize + kv->keysize);
kv->maxitemind = kv->numvalid = kv->numitems = 0;
if ( strcmp("txids",kv->name) == 0 )
coin->txids = kv;
else if ( strcmp("pkhashes",kv->name) == 0 )
coin->pkhashes = kv;
printf("kv.%p chain.%p\n",kv,coin->chain);
(*inititem)(coin,kv,0,0,-1,valuesize,0);
iguana_loadkvfile(coin,kv,valuesize,verifyitem,inititem,maxind);
if ( initialnumitems != 0 )
iguana_kvensure(coin,kv,initialnumitems);
return(kv);
}
uint32_t iguana_syncs(struct iguana_info *coin)
{
FILE *fp; char fnameold[512],fnameold2[512],fname[512],fname2[512]; int32_t i,height,flag = 0;
if ( (coin->blocks.parsedblocks > coin->longestchain-1000 && (coin->blocks.parsedblocks % 100) == 1) ||
(coin->blocks.parsedblocks > coin->longestchain-10000 && (coin->blocks.parsedblocks % 1000) == 1) ||
(coin->blocks.parsedblocks > coin->longestchain-2000000 && (coin->blocks.parsedblocks % 10000) == 1) ||
(coin->blocks.parsedblocks > coin->firstblock+100 && (coin->blocks.parsedblocks % 100000) == 1) )
{
if ( coin->blocks.parsedblocks > coin->loadedLEDGER.snapshot.height+2 )
flag = 1;
}
if ( flag != 0 )
{
height = coin->blocks.parsedblocks - (coin->firstblock != 0);
for (i=0; i<IGUANA_NUMAPPENDS; i++)
printf("%llx ",(long long)coin->LEDGER.snapshot.lhashes[i].txid);
char str[65];
bits256_str(str,coin->LEDGER.snapshot.ledgerhash);
printf("-> syncs %s ledgerhashes.%d\n",str,height);
//iguana_syncmap(&coin->iAddrs->M,0);
iguana_syncmap(&coin->blocks.db->M,0);
iguana_syncmap(&coin->unspents->M,0);
iguana_syncmap(&coin->unspents->M2,0);
iguana_syncmap(&coin->spends->M,0);
iguana_syncmap(&coin->spends->M2,0);
iguana_syncmap(&coin->txids->M,0);
iguana_syncmap(&coin->pkhashes->M,0);
iguana_syncmap(&coin->pkhashes->M2,0);
iguana_syncmap(&coin->pkhashes->M3,0);
printf("%s threads.%d iA.%d ranked.%d hwm.%u parsed.%u T.%d U.%d %.8f S.%d %.8f net %.8f P.%d\n",coin->symbol,iguana_numthreads(coin,-1),coin->numiAddrs,coin->peers.numranked,coin->blocks.hwmheight+1,height,coin->latest.dep.numtxids,coin->latest.dep.numunspents,dstr(coin->latest.credits),coin->latest.dep.numspends,dstr(coin->latest.debits),dstr(coin->latest.credits)-dstr(coin->latest.debits),coin->latest.dep.numpkinds);
sprintf(fname,"tmp/%s/ledger.%d",coin->symbol,height);
sprintf(fname2,"DB/%s/ledger",coin->symbol);
sprintf(fnameold,"tmp/%s/ledger.old",coin->symbol);
sprintf(fnameold2,"tmp/%s/ledger.old2",coin->symbol);
iguana_renamefile(fnameold,fnameold2);
iguana_renamefile(fname2,fnameold);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( fwrite(coin->accounts,sizeof(*coin->accounts),coin->LEDGER.snapshot.dep.numpkinds,fp) != coin->LEDGER.snapshot.dep.numpkinds )
printf("WARNING: error saving %s accounts[%d]\n",fname,coin->LEDGER.snapshot.dep.numpkinds);
if ( fwrite(&coin->LEDGER,1,sizeof(coin->LEDGER),fp) != sizeof(coin->LEDGER) )
printf("WARNING: error saving %s\n",fname);
fclose(fp);
iguana_copyfile(fname,fname2,1);
}
printf("backups created\n");
}
return((uint32_t)time(NULL));
}
// 480a886f78a52d94 2c16330bdd8565f2 fbfb8ba91a6cd871 d1feb1e96190d4ff b8fef8854847e7db 8d2692bcfe41c777 ec86c8502288022f 789ebb3966bb640f -> pre parse 35ee0080a9a132e88477e8809a6e2a0696a06b8c7b13fbfde2955998346dd5c8 ledgerhashes.120000
// 9d1025feba33725a d69751b2f8d3f626 1f19457ce24411f1 76e12fd68b3b5b3c 2ad1a1e4b3b7014e a699f2904d073771 989c145c04a7a0d0 e888ab12de678518 -> syncs b8cf6b625de1d921695d1d2247ad68b86d047adf417c09562dc620ada993c47d ledgerhashes.140000
// 53faf4c08ae7cd66 60af0f6074a4460a 8fa0f21eb4996161 7d695aa60788e52c 45a5c96ef55a1797 7b3225a83646caec d2d5788986315066 27372b0616caacf0 -> syncs c874aa3554c69038574e7da352eb624ac539fed97bf73b605d00df0c8cec4c1b ledgerhashes.200000
// 739df50dbbaedada b83cbd69f08d2a0f 7a8ffa182706c5b7 8215ff6c7ffb9985 4d674a6d386bd759 f829283534a1804 aeb3b0644b01e07f 7ffe4899a261ca96 -> syncs fba47203d5c1d08e5cf55fa461f4deb6d0c97dcfa364ee5b51f0896ffcbcbaa7 ledgerhashes.300000
// 739df50dbbaedada b83cbd69f08d2a0f 7a8ffa182706c5b7 8215ff6c7ffb9985 4d674a6d386bd759 f829283534a1804 b5e66cbe3a2bdbea 7ffe4899a261ca96 -> syncs 6b3620ba67fad34a29dd86cd5ec9fe6afd2a81d8a5296aa33b03da74fdd20a9b ledgerhashes.300001
int32_t iguana_loadledger(struct iguana_info *coin,int32_t hwmheight)
{
FILE *fp; char fname[512],mapname[512],newfname[512]; struct iguana_block *block; struct iguana_prevdep L;
struct iguana_prevdep *dep; int32_t height,i,valid = 0;
dep = &coin->latest.dep;
sprintf(fname,"DB/%s/ledger",coin->symbol);
mapname[0] = newfname[0] = 0;
if ( (fp= fopen(fname,"rb")) == 0 )
{
sprintf(fname,"tmp/%s/ledger.old",coin->symbol);
if ( (fp= fopen(fname,"rb")) == 0 )
{
sprintf(fname,"tmp/%s/ledger.old2",coin->symbol);
fp = fopen(fname,"rb");
}
}
if ( fp != 0 )
{
sprintf(mapname,"DB/%s/pkhashes2",coin->symbol);
sprintf(newfname,"DB/%s/pkhashes2.over",coin->symbol);
fseek(fp,-sizeof(coin->LEDGER),SEEK_END);
if ( fread(&coin->LEDGER,1,sizeof(coin->LEDGER),fp) != sizeof(coin->LEDGER) )
printf("WARNING: error loading %s\n",fname);
if ( (block= iguana_blockptr(coin,coin->LEDGER.snapshot.height)) != 0 )
{
if ( memcmp(block->hash2.bytes,coin->LEDGER.snapshot.blockhash.bytes,sizeof(block->hash2)) == 0 )
{
fclose(fp);
iguana_renamefile(mapname,newfname);
iguana_renamefile(fname,mapname);
*dep = coin->LEDGER.snapshot.dep;
coin->loadedLEDGER = coin->LEDGER;
memcpy(&coin->latest.ledgerhash,&coin->LEDGER.snapshot.ledgerhash,sizeof(coin->LEDGER.snapshot.ledgerhash));
memcpy(coin->latest.lhashes,coin->LEDGER.snapshot.lhashes,sizeof(coin->LEDGER.snapshot.lhashes));
memcpy(coin->latest.states,coin->LEDGER.snapshot.states,sizeof(coin->LEDGER.snapshot.states));
printf("found ledger height.%d loadedht.%d\n",block->height,coin->LEDGER.snapshot.height); //getchar();
for (i=0; i<IGUANA_NUMAPPENDS; i++)
printf("%llx ",(long long)coin->LEDGER.snapshot.lhashes[i].txid);
char str[65];
bits256_str(str,coin->LEDGER.snapshot.ledgerhash);
printf("-> %s ledgerhashes.%x\n",str,calc_crc32(0,&coin->latest.states[IGUANA_LHASH_TXIDS],sizeof(coin->latest.states[IGUANA_LHASH_TXIDS])));
printf("loaded H.%d T%d U%d S%d P%d\n",coin->LEDGER.snapshot.height,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds); //getchar();
coin->latest.credits = coin->LEDGER.snapshot.credits;
coin->latest.debits = coin->LEDGER.snapshot.debits;
coin->latest.dep.supply = (coin->LEDGER.snapshot.credits - coin->LEDGER.snapshot.debits);
return(block->height);
}
}
fclose(fp);
}
dep->numpkinds = dep->numtxids = dep->numunspents = dep->numspends = 1;
while ( hwmheight > 0 )
{
if ( (block= iguana_blockptr(coin,hwmheight)) != 0 )
{
iguana_setdependencies(coin,block,&L);
//printf("block.%d: T.%d (%d %d) U.%d S.%d A.%d\n",hwmheight,dep->numtxids,block->numvouts,block->numvins,dep->numunspents,dep->numspends,dep->numpkhashes);
if ( L.numtxids != 0 && L.numunspents != 0 && L.numspends != 0 && block->numvouts != 0 && block->txn_count != 0 && L.numpkinds != 0 )
{
if ( valid++ > 25 )
break;
}
} else printf("missing block.%d\n",hwmheight);
hwmheight--;
}
for (height=0; height<=hwmheight; height++)
{
if ( iguana_setdependencies(coin,iguana_blockptr(coin,height),&L) < 0 )
break;
dep->numtxids = L.numtxids + 0*block->txn_count;
dep->numunspents = L.numunspents + 0*block->numvouts;
dep->numspends = L.numspends + 0*block->numvins;
dep->numpkinds = L.numpkinds;
}
return(hwmheight);
}
int32_t iguana_validateramchain(struct iguana_info *coin,int64_t *netp,uint64_t *creditsp,uint64_t *debitsp,int32_t height,struct iguana_block *block,int32_t hwmheight,struct iguana_prevdep *lp)
{
uint32_t i,n,m,u,txidind,unspentind,spendind,pkind,checkind,numvins,numvouts,txind,firstvout,firstvin,nextfirstvout,nextfirstvin; struct iguana_prevdep *nextlp;
struct iguana_txid T,nextT; uint64_t credits,debits,nets; struct iguana_block *nextblock;
credits = debits = nets = *creditsp = *debitsp = *netp = numvouts = numvins = 0;
if ( block->height == height )
{
txidind = lp->numtxids, unspentind = lp->numunspents, spendind = lp->numspends, pkind = lp->numpkinds;
//printf("validate.%d (t%d u%d s%d p%d)\n",height,txidind,unspentind,spendind,pkind);
for (txind=0; txind<block->txn_count; txind++,txidind++)
{
T = coin->T[txidind], nextT = coin->T[txidind+1];
//printf("h%d i%d T.%d (%d %d) -> (%d %d)\n",height,txind,txidind,T.firstvout,T.firstvin,nextT.firstvout,nextT.firstvin);
if ( height == 0 && (T.firstvout == 0 || T.firstvin == 0) )
return(-1);
//printf(">>>> h%d i%d T.%d (%d %d) -> (%d %d) cmp.(%d %d)\n",height,txind,txidind,T.firstvout,T.firstvin,nextT.firstvout,nextT.firstvin,height == 0,(T.firstvout == 0 || T.firstvin == 0));
if ( (checkind= iguana_txidind(coin,&firstvout,&firstvin,T.txid)) == txidind )
{
if ( T.firstvout != firstvout || T.firstvin != firstvin )
{
printf("mismatched rwtxidind %d != %d, %d != %d\n",T.firstvout,firstvout,T.firstvin,firstvin);
getchar();
return(-1);
}
if ( txind == 0 && (firstvout != unspentind || firstvin != spendind) )
{
char str[65];
bits256_str(str,T.txid);
printf("h.%d txind.%d txidind.%d %s firstvout.%d != U%d firstvin.%d != S%d\n",height,txind,txidind,str,firstvout,unspentind,firstvin,spendind);
iguana_txidind(coin,&firstvout,&firstvin,T.txid);
iguana_txidind(coin,&firstvout,&firstvin,T.txid);
return(-1);
}
nextfirstvout = nextT.firstvout, nextfirstvin = nextT.firstvin;
if ( nextfirstvout < unspentind || nextfirstvin < spendind )
{
printf("h.%d txind.%d nexttxidind.%d firstvout.%d != U%d firstvin.%d != S%d\n",height,txind,txidind,nextfirstvout,unspentind,nextfirstvin,spendind);
if ( nextfirstvout == 0 && nextfirstvin == 0 )
{
coin->T[txidind+1].firstvout = unspentind;
coin->T[txidind+1].firstvin = spendind;
printf("autofixed\n");
}
else
{
getchar();
return(-1);
}
}
n = (nextfirstvout - T.firstvout);
m = (nextfirstvin - T.firstvin);
//printf("height.%d n.%d m.%d U.(%d - %d) S.(%d - %d)\n",height,n,m,nextfirstvout,T.firstvout,nextfirstvin,T.firstvin);
for (i=0; i<n; i++,unspentind++)
{
credits += coin->U[unspentind].value;
if ( coin->Uextras[unspentind].spendind == 0 )
nets += coin->U[unspentind].value;
if ( coin->U[unspentind].pkind > pkind )
pkind = coin->U[unspentind].pkind;
//printf("i.%d: unspentind.%d\n",i,unspentind);
}
for (i=0; i<m; i++,spendind++)
{
if ( (u= coin->S[spendind].spendtxidind) > 0 && u < coin->latest.dep.numunspents )
debits += coin->U[u].value;
else
{
printf("cant read spendind.%d or S.unspentind %d\n",spendind+i,u);
getchar();
}
}
numvouts += n;
numvins += m;
}
else
{
char str[65];
bits256_str(str,T.txid);
printf("height.%d txind.%d txid.%s txidind.%d != %d\n",height,txind,str,txidind,checkind);
getchar();
return(-1);
}
}
if ( numvins != block->numvins || numvouts != block->numvouts )
{
printf("height.%d numvins or numvouts error %d != %d || %d != %d\n",height,numvins,block->numvins,numvouts,block->numvouts);
if ( block->numvins == 0 && block->numvouts == 0 )
{
block->numvins = numvins;
block->numvouts = numvouts;
iguana_kvwrite(coin,coin->blocks.db,0,block,(uint32_t *)&block->height);
m = 0;//iguana_fixblocks(coin,height,hwmheight);
printf("autocorrected.%d\n",m);
exit(1);
}
else
{
getchar();
return(-1);
}
}
*creditsp = credits, *debitsp = debits, *netp = nets;
if ( (nextblock= iguana_blockptr(coin,height+1)) != 0 )
{
nextlp = 0;
if ( 0 && lp->supply+credits-debits != nextlp->supply )
{
printf("nextblock.%d supply mismatch %.8f (%.8f - %.8f) %.8f != %.8f\n",height+1,dstr(lp->supply),dstr(credits),dstr(debits),dstr(lp->supply+credits-debits),dstr(nextlp->supply));
getchar();
return(-1);
}
if ( txidind != nextlp->numtxids || unspentind != nextlp->numunspents || spendind != nextlp->numspends )//|| pkind+1 != nextlp->numpkinds )
{
printf("Block.(h%d t%d u%d s%d p%d) vs next.(h%d t%d u%d s%d p%d)\n",block->height,txidind,unspentind,spendind,pkind,height+1,nextlp->numtxids,nextlp->numunspents,nextlp->numspends,nextlp->numpkinds);
return(-1);
}
return(0);
}
printf("cant find next block at %d\n",height+1);
//printf("block.%d %.8f (%.8f - %.8f)\n",height,dstr(nets),dstr(credits),dstr(debits));
} else printf("height mismatch %d != %d\n",height,block->height);
//getchar();
return(-1);
}
int32_t iguana_fixsecondary(struct iguana_info *coin,int32_t numtxids,int32_t numunspents,int32_t numspends,int32_t numpkinds,struct iguana_Uextra *Uextras,struct iguana_pkextra *pkextras,struct iguana_account *accounts)
{
uint32_t i; int32_t m,err;
if ( numtxids < 2 || numunspents < 2 || numspends < 2 || numpkinds < 2 )
return(0);
//struct iguana_Uextra { uint32_t spendind; }; // unspentind
//struct iguana_unspent { uint64_t value; uint32_t pkind,txidind,prevunspentind; };
for (i=m=err=0; i<numunspents; i++)
{
if ( Uextras[i].spendind >= numspends )
m++, Uextras[i].spendind = 0;//, printf("%d ",Uextras[i].spendind);
if ( coin->U[i].prevunspentind != 0 && coin->U[i].prevunspentind >= i )
err++, printf("preverr.%d/%d ",coin->U[i].prevunspentind,i);
if ( coin->U[i].txidind >= numtxids )
err++, printf("errtxidind.%d ",coin->U[i].txidind);
if ( coin->U[i].pkind >= numpkinds )
err++, printf("errpkind.%d ",coin->U[i].pkind);
}
if ( (err+m) != 0 )
iguana_syncmap(&coin->unspents->M2,0);
printf("cleared %d Uextras before numunspents.%d beyond errs.%d\n",m,numunspents,err);
if ( err != 0 )
getchar();
//struct iguana_pkextra { uint32_t firstspendind; }; // pkind
for (i=m=0; i<numpkinds; i++)
{
if ( pkextras[i].firstspendind >= numspends )
m++, pkextras[i].firstspendind = 0;//, printf("firstS.%d ",pkextras[i].firstspendind);
}
if ( m != 0 )
iguana_syncmap(&coin->pkhashes->M3,0);
printf("pkextras beyond numspends.%d m.%d accounts.%p\n",numspends,m,accounts);
//struct iguana_spend { uint32_t unspentind,prevspendind; }; // dont need nextspend
/*for (i=err=m=0; i<numspends; i++)
{
if ( coin->S[i].unspentind >= numunspents )
err++, coin->S[i].unspentind = 0;//, printf("S->U%d ",coin->S[i].unspentind);
//printf("%d ",coin->S[i].prevspendind);
if ( coin->Sextras[i].prevspendind != 0 && coin->Sextras[i].prevspendind >= i )
m++, coin->Sextras[i].prevspendind = 0, printf("preverr.%d:%d ",coin->Sextras[i].prevspendind,i);
}
printf("errs.%d in spends numspends.%d\n",err,numspends);
if ( err != 0 )
getchar();*/
return(0);
}
void clearmem(void *ptr,int32_t len)
{
static const uint8_t zeroes[512];
if ( len > sizeof(zeroes) || memcmp(ptr,zeroes,len) != 0 )
memset(ptr,0,len);
}
int32_t iguana_clearoverage(struct iguana_info *coin,int32_t numtxids,int32_t numunspents,int32_t numspends,int32_t numpkinds,struct iguana_Uextra *Uextras,struct iguana_pkextra *pkextras,struct iguana_account *accounts)
{
uint32_t i,n;
printf("clear txids\n");
n = (uint32_t)((uint64_t)coin->txids->M.allocsize / coin->txids->HDDvaluesize) - 2;
for (i=numtxids+1; i<n; i++) // diff with next txid's firstv's give numv's
clearmem(&coin->T[i],sizeof(coin->T[i]));
printf("clear pkinds\n");
n = (uint32_t)((uint64_t)coin->pkhashes->M.allocsize / coin->pkhashes->HDDvaluesize) - 2;
for (i=numpkinds; i<n; i++)
clearmem(&coin->P[i],sizeof(coin->P[i]));
n = (uint32_t)((uint64_t)coin->pkhashes->M2.allocsize / coin->pkhashes->valuesize2) - 2;
for (i=numpkinds; i<n; i++)
clearmem(&accounts[i],sizeof(accounts[i]));
n = (uint32_t)((uint64_t)coin->pkhashes->M3.allocsize / coin->pkhashes->valuesize3) - 2;
for (i=numpkinds; i<n; i++)
pkextras[i].firstspendind = 0;
printf("clear unspents\n");
n = (uint32_t)((uint64_t)coin->unspents->M.allocsize / coin->unspents->HDDvaluesize) - 2;
for (i=numunspents; i<n; i++)
clearmem(&coin->U[i],sizeof(coin->U[i]));
n = (uint32_t)((uint64_t)coin->unspents->M2.allocsize / coin->unspents->valuesize2) - 2;
for (i=numunspents; i<n; i++)
clearmem(&Uextras[i],sizeof(Uextras[i]));
printf("clear spends\n");
n = (uint32_t)((uint64_t)coin->spends->M.allocsize / coin->spends->HDDvaluesize) - 2;
for (i=numspends; i<n; i++)
clearmem(&coin->S[i],sizeof(coin->S[i]));
//n = (uint32_t)((uint64_t)coin->spends->M2.allocsize / coin->spends->valuesize2) - 2;
//for (i=numspends; i<n; i++)
// clearmem(&coin->Sextras[i],sizeof(coin->Sextras[i]));
return(0);
}
int64_t iguana_verifybalances(struct iguana_info *coin,int32_t fullverify)
{
int64_t err,balance = 0; int32_t i,numerrs = 0;
for (i=0; i<coin->latest.dep.numpkinds; i++)
{
if ( fullverify != 0 )
{
if ( (err= iguana_verifyaccount(coin,&coin->accounts[i],i)) < 0 )
{
printf("err.%d from pkind.%d\n",(int32_t)err,i);
numerrs++;
}
}
balance += coin->accounts[i].balance;
}
printf("iguana_verifybalances %.8f numerrs.%d\n",dstr(balance),numerrs);
if ( numerrs > 0 )
getchar();
return(balance);
}
int32_t iguana_initramchain(struct iguana_info *coin,int32_t hwmheight,int32_t mapflags,int32_t fullverify)
{
struct iguana_prevdep *dep; struct iguana_block *block,lastblock; double lastdisp = 0.;
// init sequence is very tricky. must be done in the right order and make sure to only use data
// that has already been initialized. and at the end all the required fields need to be correct
struct iguana_msghdr H; uint8_t buf[1024]; int32_t len,height,valid=0,flag=0;
struct iguana_prevdep L,prevL;
int64_t checkbalance,net,nets; uint64_t prevcredits,prevdebits,credit,debit,credits,debits,origsupply;
dep = &coin->latest.dep;
height = hwmheight;
if ( (height= iguana_loadledger(coin,hwmheight)) < 0 )
{
printf("iguana_initramchain: unrecoverable loadledger error hwmheight.%d\n",hwmheight);
return(-1);
}
hwmheight = height;
printf("four ramchains start valid.%d height.%d txids.%d vouts.%d vins.%d pkhashes.%d\n",valid,hwmheight,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds);
//four ramchains start valid.0 height.316904 txids.45082870 vouts.27183907 vins.107472009 pkhashes.44807925 3.57 minutes
coin->unspents = iguana_stateinit(coin,IGUANA_ITEMIND_DATA,coin->symbol,coin->symbol,"unspents",0,0,sizeof(struct iguana_unspent),sizeof(struct iguana_unspent),100000,iguana_verifyunspent,iguana_nullinit,sizeof(*coin->Uextras),0,dep->numunspents,2500000,0);
if ( coin->unspents == 0 )
printf("cant create unspents\n"), exit(1);
coin->unspents->HDDitemsp = (void **)&coin->U, coin->U = coin->unspents->M.fileptr;
coin->unspents->HDDitems2p = (void **)&coin->Uextras, coin->Uextras = coin->unspents->M2.fileptr;
printf("four ramchains start valid.%d height.%d txids.%d vouts.%d vins.%d pkhashes.%d %.2f minutes\n",valid,hwmheight,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds,((double)time(NULL)-coin->starttime)/60.);
coin->spends = iguana_stateinit(coin,IGUANA_ITEMIND_DATA,coin->symbol,coin->symbol,"spends",0,0,sizeof(struct iguana_spend),sizeof(struct iguana_spend),100000,iguana_verifyspend,iguana_nullinit,0,0,dep->numspends,2500000,0);
if ( coin->spends == 0 )
printf("cant create spends\n"), exit(1);
printf("four ramchains start valid.%d height.%d txids.%d vouts.%d vins.%d pkhashes.%d %.2f minutes\n",valid,hwmheight,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds,((double)time(NULL)-coin->starttime)/60.);
coin->spends->HDDitemsp = (void **)&coin->S, coin->S = coin->spends->M.fileptr;
coin->spends->HDDitems2p = (void **)&coin->Sextras, coin->Sextras = coin->spends->M2.fileptr;
coin->txids = iguana_stateinit(coin,IGUANA_ITEMIND_DATA|((mapflags&IGUANA_MAPTXIDITEMS)!=0)*IGUANA_MAPPED_ITEM,coin->symbol,coin->symbol,"txids",0,sizeof(bits256),sizeof(struct iguana_txid),sizeof(struct iguana_txid),100000,iguana_verifytxid,iguana_inittxid,0,0,dep->numtxids,1000000,0);
if ( coin->txids == 0 )
printf("cant create txids\n"), exit(1);
coin->txids->HDDitemsp = (void **)&coin->T, coin->T = coin->txids->M.fileptr;
printf("four ramchains start valid.%d height.%d txids.%d vouts.%d vins.%d pkhashes.%d %.2f minutes\n",valid,hwmheight,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds,((double)time(NULL)-coin->starttime)/60.);
coin->pkhashes = iguana_stateinit(coin,IGUANA_ITEMIND_DATA|((mapflags&IGUANA_MAPPKITEMS)!=0)*IGUANA_MAPPED_ITEM,coin->symbol,coin->symbol,"pkhashes",0,20,sizeof(struct iguana_pkhash),sizeof(struct iguana_pkhash),100000,iguana_verifypkhash,iguana_nullinit,sizeof(*coin->accounts),sizeof(*coin->pkextras),dep->numpkinds,1000000,0);
if ( coin->pkhashes == 0 )
printf("cant create pkhashes\n"), exit(1);
coin->pkhashes->HDDitemsp = (void **)&coin->P, coin->P = coin->pkhashes->M.fileptr;
coin->pkhashes->HDDitems2p = (void **)&coin->accounts, coin->accounts = coin->pkhashes->M2.fileptr;
coin->pkhashes->HDDitems3p = (void **)&coin->pkextras, coin->pkextras = coin->pkhashes->M3.fileptr;
printf("four ramchains start valid.%d height.%d txids.%d vouts.%d vins.%d pkhashes.%d %.2f minutes\n",valid,hwmheight,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds,((double)time(NULL)-coin->starttime)/60.);
iguana_kvensure(coin,coin->txids,dep->numtxids + coin->txids->incr);
iguana_kvensure(coin,coin->pkhashes,dep->numpkinds + coin->pkhashes->incr);
iguana_kvensure(coin,coin->unspents,dep->numunspents + coin->unspents->incr);
iguana_kvensure(coin,coin->spends,dep->numspends + coin->spends->incr);
coin->txids->numkeys = dep->numtxids;
coin->unspents->numkeys = dep->numunspents;
coin->spends->numkeys = dep->numspends;
coin->pkhashes->numkeys = dep->numpkinds;
iguana_fixsecondary(coin,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds,coin->Uextras,coin->pkextras,coin->accounts);
printf("hwmheight.%d KV counts T.%d P.%d U.%d S.%d\n",hwmheight,coin->txids->numkeys,coin->pkhashes->numkeys,coin->unspents->numkeys,coin->spends->numkeys);
memset(&lastblock,0,sizeof(lastblock));
origsupply = dep->supply, dep->supply = 0;
for (prevcredits=prevdebits=credits=debits=nets=height=0; height<=hwmheight; height++)
{
if ( hwmheight > 10000 && ((double)height / hwmheight) > lastdisp+.01 )
{
fprintf(stderr,"%.0f%% ",100. * lastdisp);
lastdisp = ((double)height / hwmheight);
}
if ( (block= iguana_blockptr(coin,height)) == 0 )
{
printf("error getting height.%d\n",height);
break;
}
lastblock = *block;
if ( height == hwmheight )
break;
printf("need to set valid L\n");
if ( iguana_validateramchain(coin,&net,&credit,&debit,height,block,hwmheight,&L) < 0 )
{
printf("UNRECOVERABLE error iguana_validateramchain height.%d\n",height);
getchar();
exit(1);
break;
}
nets += net, credits += credit, debits += debit;
if ( nets != (credits - debits) )
{
//printf("height.%d: net %.8f != %.8f (%.8f - %.8f)\n",height,dstr(nets),dstr(credits)-dstr(debits),dstr(credits),dstr(debits));
//break;
}
prevcredits = credits;
prevdebits = debits;
}
if ( lastblock.height == 0 )
dep->numpkinds = dep->numspends = dep->numtxids = dep->numunspents = 1, dep->supply = 0, coin->latest.credits = coin->latest.debits = 0;
else
{
printf("set prevL\n");
dep->numtxids = prevL.numtxids;
dep->numunspents = prevL.numunspents;
dep->numspends = prevL.numspends;
dep->numpkinds = prevL.numpkinds;
dep->supply = prevL.supply;
coin->latest.credits = prevcredits;
coin->latest.debits = prevdebits;
if ( dep->supply != (prevcredits - prevdebits) )
{
printf("override supply %.8f (%.8f - %.8f)\n",dstr(dep->supply),dstr(prevcredits),dstr(prevdebits));
dep->supply = (prevcredits - prevdebits);
}
checkbalance = iguana_verifybalances(coin,0);
if ( (checkbalance != dep->supply || fullverify != 0) && iguana_verifybalances(coin,1) != dep->supply )
{
printf("balances mismatch\n");
getchar();
}
}
coin->txids->numkeys = dep->numtxids;
coin->unspents->numkeys = dep->numunspents;
coin->spends->numkeys = dep->numspends;
coin->pkhashes->numkeys = dep->numpkinds;
coin->blocks.parsedblocks = lastblock.height;
printf("\nhwmheight.%d KV counts T.%d P.%d U.%d S.%d %.8f (%.8f - %.8f)\n",hwmheight,coin->txids->numkeys,coin->pkhashes->numkeys,coin->unspents->numkeys,coin->spends->numkeys,dstr(coin->latest.dep.supply),dstr(coin->latest.credits),dstr(coin->latest.debits));
printf("four ramchains start valid.%d height.%d txids.%d vouts.%d vins.%d pkhashes.%d %.2f minutes\n",valid,hwmheight,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds,((double)time(NULL)-coin->starttime)/60.);
printf("height.%d after validateramchain hwmheight.%d flag.%d parsed.%d\n",height,hwmheight,flag,coin->blocks.parsedblocks); //getchar();
if ( coin->blocks.parsedblocks == 0 )
{
uint8_t txspace[32768]; struct iguana_memspace MEM;
len = (int32_t)strlen(coin->chain->genesis_hex)/2;
decode_hex(buf,len,(char *)coin->chain->genesis_hex);
iguana_sethdr(&H,coin->chain->netmagic,"block",buf,len);
iguana_meminit(&MEM,"genesis",txspace,sizeof(txspace),0);
iguana_parser(coin,0,&MEM,&MEM,0,&H,buf,len);
printf("coin->blocks.parsedblocks.%d KV counts T.%d P.%d U.%d S.%d\n",coin->blocks.parsedblocks,coin->txids->numkeys,coin->pkhashes->numkeys,coin->unspents->numkeys,coin->spends->numkeys);
printf("auto parse genesis\n"); //getchar();
}
else iguana_clearoverage(coin,dep->numtxids,dep->numunspents,dep->numspends,dep->numpkinds,coin->Uextras,coin->pkextras,coin->accounts);
return(coin->blocks.parsedblocks);
}
#endif
if ( 0 && queue_size(&coin->blocksQ) == 0 )
{
HASH_ITER(hh,coin->blocks.hash,block,tmp)
{
if ( bits256_nonz(block->prev_block) > 0 && (prev= iguana_blockfind(coin,block->prev_block)) != 0 )
{
if ( prev->mainchain != 0 )
{
char str[65]; printf("idle issue %s %d\n",bits256_str(str,block->hash2),prev->height+1);
iguana_blockQ(coin,0,-1,block->hash2,0);
}
}
}
}
struct iguana_ramchain *iguana_ramchainmergeHT(struct iguana_info *coin,struct iguana_memspace *mem,struct iguana_ramchain *ramchains[],int32_t n,struct iguana_bundle *bp)
{
/* uint32_t numtxids,numunspents,numspends,numpkinds,numexternaltxids,i,j,k; uint64_t allocsize = 0;
struct iguana_txid *tx; struct iguana_account *acct; struct iguana_ramchain *ramchain,*item;
struct iguana_pkhash *p,oldP; struct iguana_unspent *u; struct iguana_kvitem *ptr;
bits256 txid; uint32_t txidind,unspentind,spendind,pkind,numblocks; struct iguana_spend *s;
numtxids = numunspents = numspends = numpkinds = 1;
numexternaltxids = 1;
numblocks = 0;
for (i=0; i<n; i++)
{
if ( (item= ramchains[i]) == 0 )
{
printf("iguana_ramchaininit null hdrsi.%d txdatas[%d]\n",bp->ramchain.hdrsi,i);
return(0);
}
numtxids += item->numtxids, numunspents += item->numunspents, numspends += item->numspends;
numpkinds += item->numpkinds, numexternaltxids += item->numexternaltxids;
numblocks += item->numblocks;
}
allocsize = sizeof(*ramchain) +
(numtxids * sizeof(*ramchain->T)) +
(numunspents * (sizeof(*ramchain->U) + sizeof(*ramchain->Uextras))) +
(numspends * sizeof(*ramchain->S)) +
(numpkinds * (sizeof(*ramchain->P) + sizeof(*ramchain->pkextras) + sizeof(*ramchain->accounts))) +
(numexternaltxids * sizeof(*ramchain->externalT));
iguana_meminit(mem,"ramchain",0,allocsize,0);
mem->alignflag = sizeof(uint32_t);
ramchain= &bp->ramchain; //iguana_memalloc(mem,sizeof(*ramchain),1)) == 0 )
ramchain->numblocks = numblocks;
ramchain->numtxids = numtxids, ramchain->numunspents = numunspents;
ramchain->numspends = numspends, ramchain->numpkinds = numpkinds;
ramchain->numexternaltxids = numexternaltxids;
ramchain->hdrsi = bp->ramchain.hdrsi, ramchain->bundleheight = bp->ramchain.bundleheight, ramchain->numblocks = n;
ramchain->prevbundlehash2 = bp->prevbundlehash2, ramchain->nextbundlehash2 = bp->nextbundlehash2;
ramchain->hash2 = ramchains[0]->hash2;
ramchain->prevhash2 = ramchains[0]->prevhash2, ramchain->lasthash2 = ramchains[n-1]->hash2;
ramchain->T = iguana_memalloc(mem,sizeof(*ramchain->T) * ramchain->numtxids,0);
ramchain->U = iguana_memalloc(mem,sizeof(*ramchain->U) * ramchain->numunspents,0);
if ( ramchain->numspends > 0 )
ramchain->S = iguana_memalloc(mem,sizeof(*ramchain->S) * ramchain->numspends,0);
ramchain->Uextras = iguana_memalloc(mem,sizeof(*ramchain->Uextras) * ramchain->numunspents,1);
ramchain->P = iguana_memalloc(mem,sizeof(*ramchain->P) * ramchain->numpkinds,1);
ramchain->pkextras = iguana_memalloc(mem,sizeof(*ramchain->pkextras) * ramchain->numpkinds,1);
ramchain->accounts = iguana_memalloc(mem,sizeof(*ramchain->accounts) * ramchain->numpkinds,1);
if ( ramchain->numexternaltxids > 0 )
ramchain->externalT = iguana_memalloc(mem,ramchain->numexternaltxids * sizeof(*ramchain->externalT),1);
if ( mem->used != allocsize )
{
printf("error allocating ramchain %ld != %ld\n",(long)mem->used,(long)allocsize);
iguana_ramchainfree(coin,mem,ramchain);
return(0);
}
ramchain->allocsize = allocsize;
ramchain->firsti = 1;
//printf("Allocated %s for bp %d\n",mbstr(str,allocsize),bp->ramchain.bundleheight);
txidind = unspentind = numtxids = spendind = numunspents = numspends = numpkinds = ramchain->firsti;
numexternaltxids = 0;
for (i=0; i<n; i++)
{
if ( (item= ramchains[i]) != 0 )
{
// iguana_txid { bits256 txid; uint32_t txidind,firstvout,firstvin; uint16_t numvouts,numvins;}
for (j=item->firsti; j<item->numtxids; j++,txidind++)
{
tx = &ramchain->T[txidind];
*tx = item->T[j];
tx->txidind = txidind;
if ( (ptr= iguana_hashfind(ramchain->txids,tx->txid.bytes,sizeof(tx->txid))) != 0 )
{
printf("unexpected duplicate txid[%d]\n",txidind);
iguana_ramchainfree(coin,mem,ramchain);
return(0);
}
iguana_hashsetHT(ramchain->txids,0,tx->txid.bytes,sizeof(bits256),txidind);
tx->firstvout = unspentind;
for (k=item->firsti; k<tx->numvouts; k++,unspentind++)
{
u = &ramchain->U[unspentind];
*u = item->U[k];
u->txidind = txidind;
oldP = item->P[item->U[k].pkind];
if ( (ptr= iguana_hashfind(ramchain->pkhashes,oldP.rmd160,sizeof(oldP.rmd160))) == 0 )
{
pkind = numpkinds++;
p = &ramchain->P[pkind];
*p = oldP;
p->firstunspentind = unspentind;
if ( (ptr= iguana_hashsetHT(ramchain->pkhashes,0,p->rmd160,sizeof(p->rmd160),numpkinds)) == 0 )
{
iguana_ramchainfree(coin,mem,ramchain);
printf("fatal error adding pkhash\n");
return(0);
}
//printf("pkind.%d: %p %016lx <- %016lx\n",pkind,p,*(long *)p->rmd160,*(long *)oldP.rmd160);
} else pkind = ptr->hh.itemind;
u->pkind = pkind;
acct = &ramchain->accounts[pkind];
u->prevunspentind = acct->lastunspentind;
acct->lastunspentind = unspentind;
acct->balance += u->value;
}
tx->firstvin = spendind;
spendind += tx->numvins;
}
numtxids += item->numtxids, numunspents += item->numunspents;
}
}
txidind = spendind = ramchain->firsti;
for (i=0; i<n; i++)
{
if ( (item= ramchains[i]) != 0 )
{
for (j=item->firsti; j<item->numtxids; j++,txidind++)
{
tx = &ramchain->T[j];
for (k=item->firsti; k<tx->numvins; k++)
{
//printf("item.%p [%d] X.%p i.%d j.%d k.%d txidind.%d/%d spendind.%d/%d s->txidind.%d/v%d\n",item,item->numexternaltxids,item->externalT,i,j,k,txidind,ramchain->numtxids,spendind,ramchain->numspends,item->S[k].spendtxidind,item->S[k].vout);
if ( iguana_ramchaintxid(coin,&txid,item,&item->S[k]) < 0 )
{
printf("i.%d j.%d k.%d error getting txid firsti.%d X.%d vout.%d spend.%d/%d numX.%d numT.%d\n",i,j,k,item->firsti,item->S[k].external,item->S[k].vout,item->S[k].spendtxidind,item->numspends,item->numexternaltxids,item->numtxids);
//iguana_ramchainfree(coin,mem,ramchain);
//return(0);
}
s = &ramchain->S[spendind];
*s = item->S[k];
if ( s->vout == 0xffff )
{
// mining output
}
else if ( (ptr= iguana_hashfind(ramchain->txids,txid.bytes,sizeof(txid))) != 0 )
{
if ( (s->spendtxidind= ptr->hh.itemind) >= ramchain->numtxids )
{
s->external = 1;
s->spendtxidind -= ramchain->numtxids;
}
else if ( s->spendtxidind >= item->firsti && s->spendtxidind < item->numtxids )
{
s->external = 0;
unspentind = (ramchain->T[s->spendtxidind].firstvout + s->vout);
u = &ramchain->U[unspentind];
p = &ramchain->P[u->pkind];
if ( ramchain->pkextras[u->pkind].firstspendind == 0 )
ramchain->pkextras[u->pkind].firstspendind = spendind;
acct = &ramchain->accounts[u->pkind];
s->prevspendind = acct->lastspendind;
acct->lastspendind = spendind;
if ( ramchain->Uextras[unspentind].spendind != 0 )
{
printf("double spend u.%d has spendind.%d when s.%d refers to it\n",unspentind,ramchain->Uextras[unspentind].spendind,spendind);
iguana_ramchainfree(coin,mem,ramchain);
return(0);
}
ramchain->Uextras[unspentind].spendind = spendind;
}
spendind++;
}
else if ( numexternaltxids < ramchain->numexternaltxids )
{
s->external = 1;
ramchain->externalT[numexternaltxids] = txid;
iguana_hashsetHT(ramchain->txids,0,ramchain->externalT[numexternaltxids].bytes,sizeof(ramchain->externalT[numexternaltxids]),ramchain->numtxids + numexternaltxids);
s->spendtxidind = numexternaltxids++;
spendind++;
}
else printf("numexternaltxids.%d >= ramchain numexternaltxids.%d\n",numexternaltxids,ramchain->numexternaltxids);
}
}
// iguana_unspent { uint64_t value; uint32_t txidind,pkind,prevunspentind; } iguana_Uextra { uint32_t spendind; }
// iguana_pkhash { uint8_t rmd160[20]; uint32_t firstunspentind,flags; } iguana_pkextra { uint32_t firstspendind; }
// iguana_account { uint64_t balance; uint32_t lastunspentind,lastspendind; }
// iguana_spend { uint32_t unspentind,prevspendind:31,diffsequence:1; }
numspends += item->numspends;
}
}
//for (i=0; i<numpkinds; i++)
// printf("have pkind.%d: %p %016lx\n",i,&ramchain->P[i],*(long *)ramchain->P[i].rmd160);
//printf("numpkinds.%d\n",numpkinds);
if ( 0 )
{
memcpy(&ramchain->P[numpkinds],ramchain->pkextras,sizeof(*ramchain->pkextras) * numpkinds);
ramchain->pkextras = (void *)&ramchain->P[numpkinds];
memcpy(&ramchain->pkextras[numpkinds],ramchain->accounts,sizeof(*ramchain->accounts) * numpkinds);
ramchain->accounts = (void *)&ramchain->pkextras[numpkinds];
memcpy(&ramchain->accounts[numpkinds],ramchain->externalT,sizeof(*ramchain->externalT) * numexternaltxids);
ramchain->externalT = (void *)&ramchain->accounts[numpkinds];
}
ramchain->allocsize -= ((ramchain->numpkinds - numpkinds) * (sizeof(*ramchain->P) + sizeof(*ramchain->pkextras) + sizeof(*ramchain->accounts)));
ramchain->allocsize -= ((ramchain->numexternaltxids - numexternaltxids) * sizeof(*ramchain->externalT));
ramchain->numpkinds = numpkinds;
ramchain->numexternaltxids = numexternaltxids;*/
/*vupdate_sha256(ramchain->lhashes[IGUANA_LHASH_UNSPENT].bytes,&ramchain->states[IGUANA_LHASH_UNSPENT],(void *)ramchain->U,sizeof(*ramchain->U)*ramchain->numunspents);
vupdate_sha256(ramchain->lhashes[IGUANA_LHASH_ACCOUNTS].bytes,&ramchain->states[IGUANA_LHASH_ACCOUNTS],(void *)acct,sizeof(*acct));
vupdate_sha256(ramchain->lhashes[IGUANA_LHASH_SPENDS].bytes,&ramchain->states[IGUANA_LHASH_SPENDS],(void *)ramchain->S,sizeof(*ramchain->S)*);
vupdate_sha256(ramchain->lhashes[IGUANA_LHASH_TXIDS].bytes,&ramchain->states[IGUANA_LHASH_TXIDS],(void *)tx,sizeof(*tx));*/
/*mem->used = (long)ramchain->allocsize;
printf("B.%d T.%d U.%d S.%d P.%d combined ramchain size.%ld\n",ramchain->numblocks,ramchain->numtxids,ramchain->numunspents,ramchain->numspends,ramchain->numpkinds,(long)ramchain->allocsize);
return(ramchain);*/
return(0);
}
/*
//if ( num > coin->chain->bundlesize+1 )
// num = coin->chain->bundlesize+1;
for (i=1; i<num; i++)
{
block = 0;
if ( bits256_nonz(blockhashes[i]) > 0 )
{
if ( (block= iguana_blockhashset(coin,-1,blockhashes[i],1)) != 0 && prev != 0 )
{
//if ( prev->mainchain == 0 )
// prev->hh.next = block;
/*if ( prev->hh.next == 0 && block->hh.prev == 0 )
block->hh.prev = prev;
else if ( prev->hh.next == 0 && block->hh.prev == prev )
prev->hh.next = block;
else if ( prev->hh.next == block && block->hh.prev == prev )
{
if ( 0 && i < coin->chain->bundlesize )
{
if ( iguana_bundlehash2add(coin,0,bp,i,blockhashes[i]) < 0 )
{
if ( prev->mainchain == 0 )
block->hh.prev = prev->hh.next = 0;
memset(bp->hashes[i].bytes,0,sizeof(bp->hashes[i]));
}
}
else if ( 0 && bp->bundleheight + coin->chain->bundlesize >= coin->bundlescount*coin->chain->bundlesize )
{
char str[65]; printf("AUTOCREATE.%d new bundle.%s\n",bp->bundleheight + coin->chain->bundlesize,bits256_str(str,blockhashes[i]));
iguana_bundlecreate(coin,&bundlei,bp->bundleheight + coin->chain->bundlesize,blockhashes[i]);
for (j=2; j<num; j++)
iguana_blockQ(coin,bp,j,blockhashes[j],0);
}
}
else if ( prev->mainchain == 0 )
block->hh.prev = prev->hh.next = 0;
}
//if ( (i % coin->chain->bundlesize) <= 1 )
// iguana_blockQ(coin,0,-1,blockhashes[i],1);
//else //if ( bp != 0 && i < bp->n && bp->requests[i] == 0 )
// iguana_blockQ(coin,0,-1,blockhashes[i],0);
}
prev = block;
}*/
int32_t iguana_ROmapchain(uint32_t *numtxidsp,uint32_t *numunspentsp,uint32_t *numspendsp,uint32_t *numpkindsp,uint32_t *numexternaltxidsp,struct iguana_ramchain *mapchain,void *ptr,long filesize,long fpos,bits256 firsthash2,bits256 lasthash2,int32_t height,int32_t numblocks,int32_t hdrsi,int32_t bundlei)
{
int32_t firsti = 1;
mapchain->fileptr = ptr;
mapchain->filesize = filesize;
mapchain->H.data = (void *)((long)ptr + fpos);
mapchain->H.ROflag = 1;
if ( iguana_ramchain_size(mapchain) != mapchain->H.data->allocsize || fpos+mapchain->H.data->allocsize > filesize )
{
printf("iguana_bundlesaveHT size mismatch %ld vs %ld vs filesize.%ld\n",(long)iguana_ramchain_size(mapchain),(long)mapchain->H.data->allocsize,(long)filesize);
return(-1);
}
else if ( memcmp(firsthash2.bytes,mapchain->H.data->firsthash2.bytes,sizeof(bits256)) != 0 )
{
char str[65],str2[65]; printf("iguana_bundlesaveHT hash2 mismatch %s vs %s\n",bits256_str(str,firsthash2),bits256_str(str2,mapchain->H.data->firsthash2));
return(-1);
}
iguana_ramchain_link(mapchain,firsthash2,lasthash2,hdrsi,height,bundlei,1,firsti,1);
*numtxidsp += mapchain->H.data->numtxids;
*numunspentsp += mapchain->H.data->numunspents;
*numspendsp += mapchain->H.data->numspends;
if( mapchain->H.data->numpkinds != 0 )
*numpkindsp += mapchain->H.data->numpkinds;
else *numpkindsp += mapchain->H.data->numunspents;
if( mapchain->H.data->numexternaltxids != 0 )
*numexternaltxidsp += mapchain->H.data->numspends;
else *numexternaltxidsp += mapchain->H.data->numspends;
//printf("(%d %d %d) ",numtxids,numunspents,numspends);
//printf("%d ",numtxids);
return(0);
}
bits256 iguana_lhashcalc(struct iguana_info *coin,struct iguana_ramchaindata *rdata,RAMCHAIN_FUNC)
{
bits256 sha256;
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_TXIDS].bytes,(uint8_t *)T,sizeof(struct iguana_txid)*rdata->numtxids);
if ( ramchain->expanded != 0 )
{
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_UNSPENTS].bytes,(uint8_t *)Ux,sizeof(struct iguana_unspent)*rdata->numunspents);
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_SPENDS].bytes,(uint8_t *)Sx,sizeof(struct iguana_spend)*rdata->numspends);
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_PKHASHES].bytes,(uint8_t *)P,sizeof(struct iguana_pkhash)*rdata->numpkinds);
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_SPENTINDS].bytes,(uint8_t *)U2,sizeof(struct iguana_Uextra)*rdata->numunspents);
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_FIRSTSPENDS].bytes,(uint8_t *)P2,sizeof(struct iguana_pkextra)*rdata->numpkinds);
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_ACCOUNTS].bytes,(uint8_t *)A,sizeof(struct iguana_account)*rdata->numpkinds);
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_EXTERNALS].bytes,(uint8_t *)X,sizeof(bits256)*rdata->numexternaltxids);
}
else
{
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_UNSPENTS].bytes,(uint8_t *)U,sizeof(struct iguana_unspent20)*rdata->numunspents);
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_SPENDS].bytes,(uint8_t *)S,sizeof(struct iguana_spend256)*rdata->numspends);
}
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_TXBITS].bytes,TXbits,(int32_t)hconv_bitlen(rdata->numtxsparse*rdata->txsparsebits));
vcalc_sha256(0,rdata->lhashes[IGUANA_LHASH_PKBITS].bytes,PKbits,(int32_t)hconv_bitlen(rdata->numpksparse*rdata->pksparsebits));
memset(&rdata->sha256,0,sizeof(rdata->sha256));
vcalc_sha256(0,sha256.bytes,(void *)rdata,sizeof(*rdata));
}
/*struct iguana_prevdep
{
double PoW; // yes I know this is not consensus safe, it is used only for approximations locally
uint64_t supply;
uint32_t numtxids,numunspents,numspends,numpkinds;
} __attribute__((packed));
struct iguanakv
{
char name[63],fname[512],threadsafe; FILE *fp;
portable_mutex_t KVmutex,MMlock,MMmutex;
void *HDDitems,*HDDitems2,*HDDitems3,**HDDitemsp,**HDDitems2p,**HDDitems3p; // linear array of HDDitems;
struct iguana_kvitem *hashtables[0x100]; // of HDDitems
struct iguana_mappedptr M,M2,M3;
struct iguana_memspace HASHPTRS;//,MEM;
double mult;
uint64_t updated;
int32_t keysize,keyoffset,RAMvaluesize,HDDvaluesize,valuesize2,valuesize3;
int32_t numkeys,dispflag,flags,incr,numitems,numvalid,maxitemind;
uint32_t iteruarg; int32_t iterarg;
uint8_t *space;
};*/
rdata->txsparsebits = hcalc_bitsize(numtxids);
rdata->numtxsparse = SPARSECOUNT(numtxids);
rdata->pksparsebits = hcalc_bitsize(numpkinds);
rdata->numpksparse = SPARSECOUNT(numpkinds);
rdata->Toffset = offset, offset += (sizeof(struct iguana_txid) * numtxids);
if ( ramchain->expanded != 0 )
{
rdata->Uoffset = offset, offset += (sizeof(struct iguana_unspent) * numunspents);
rdata->Soffset = offset, offset += (sizeof(struct iguana_spend) * numspends);
rdata->Poffset = offset, offset += (sizeof(struct iguana_pkhash) * numpkinds);
rdata->U2offset = offset, offset += (sizeof(struct iguana_Uextra) * numunspents);
rdata->P2offset = offset, offset += (sizeof(struct iguana_pkextra) * numpkinds);
rdata->Aoffset = offset, offset += (sizeof(struct iguana_account) * numpkinds);
rdata->Xoffset = offset, offset += (sizeof(bits256) * numexternaltxids);
}
else
{
rdata->Uoffset = offset, offset += (sizeof(struct iguana_unspent20) * numunspents);
rdata->Soffset = offset, offset += (sizeof(struct iguana_spend256) * numspends);
}
rdata->TXoffset = offset, offset += (((int64_t)rdata->numtxsparse*rdata->txsparsebits)/8 + 1);
rdata->PKoffset = offset, offset += (((int64_t)rdata->numpksparse*rdata->pksparsebits)/8 + 1);
tmp = *rdata;
fpos = ftell(fp);
iguana_rdata_action(0,0,&trunc,0,rdata,expanded,numtxids,numunspents,numspends,numpkinds,numexternaltxids,0,0,0,0);
offset = sizeof(*rdata);
rdata->Toffset = offset, offset += (sizeof(struct iguana_txid) * rdata->numtxids);
if ( ramchain->expanded != 0 )
{
rdata->Uoffset = offset, offset += (sizeof(struct iguana_unspent) * rdata->numunspents);
rdata->Soffset = offset, offset += (sizeof(struct iguana_spend) * rdata->numspends);
rdata->Poffset = offset, offset += (sizeof(struct iguana_pkhash) * rdata->numpkinds);
rdata->U2offset = offset, offset += (sizeof(struct iguana_Uextra) * rdata->numunspents);
rdata->P2offset = offset, offset += (sizeof(struct iguana_pkextra) * rdata->numpkinds);
rdata->Aoffset = offset, offset += (sizeof(struct iguana_account) * rdata->numpkinds);
rdata->Xoffset = offset, offset += (sizeof(bits256) * rdata->numexternaltxids);
}
else
{
rdata->Uoffset = offset, offset += (sizeof(struct iguana_unspent20) * rdata->numunspents);
rdata->Soffset = offset, offset += (sizeof(struct iguana_spend256) * rdata->numspends);
}
rdata->TXoffset = offset, offset += (((int64_t)rdata->numtxsparse*rdata->txsparsebits)/8 + 1);
rdata->PKoffset = offset, offset += (((int64_t)rdata->numpksparse*rdata->pksparsebits)/8 + 1);
rdata->allocsize = offset;
rdata->sha256 = iguana_lhashcalc(coin,rdata,RAMCHAIN_ARGS);
if ( iguana_ramchain_size(ramchain) != offset )
printf("iguana_ramchain_size %ld vs %ld\n",(long)iguana_ramchain_size(ramchain),(long)offset), getchar();
rdata->sha256 = sha256 = iguana_lhashcalc(coin,rdata,RAMCHAIN_ARG);
fwrite(rdata,1,sizeof(*rdata),fp);
*rdata = tmp;
fwrite(T,sizeof(struct iguana_txid),rdata->numtxids,fp);
if ( ramchain->expanded != 0 )
{
fwrite(Ux,sizeof(struct iguana_unspent),rdata->numunspents,fp);
fwrite(Sx,sizeof(struct iguana_spend),rdata->numspends,fp);
fwrite(P,sizeof(struct iguana_pkhash),rdata->numpkinds,fp);
fwrite(U2,sizeof(struct iguana_Uextra),rdata->numunspents,fp);
fwrite(P2,sizeof(struct iguana_pkextra),rdata->numpkinds,fp);
fwrite(A,sizeof(struct iguana_account),rdata->numpkinds,fp);
fwrite(X,sizeof(bits256),rdata->numexternaltxids,fp);
//printf("iguana_ramchain_save.(%s): (%ld - %ld) diff.%ld vs %ld [%ld]\n",fname,ftell(fp),(long)fpos,(long)(ftell(fp) - fpos),(long)rdata->allocsize,(long)(ftell(fp) - fpos) - (long)rdata->allocsize);
}
else
{
fwrite(U,sizeof(struct iguana_unspent20),rdata->numunspents,fp);
fwrite(S,sizeof(struct iguana_spend256),rdata->numspends,fp);
}
fwrite(TXbits,1,((int64_t)rdata->numtxsparse*rdata->txsparsebits)/8 + 1,fp);
fwrite(PKbits,1,((int64_t)rdata->numpksparse*rdata->pksparsebits)/8 + 1,fp);
if ( (ftell(fp) - fpos) != rdata->allocsize )
{
printf("(ftell.%ld - fpos.%ld) %ld vs %ld\n",ftell(fp),fpos,ftell(fp)-fpos,(long)rdata->allocsize);
fpos = -1;
}
//int32_t i; char str[65];
//for (i=0; i<rdata->numexternaltxids; i++)
// printf("X[%d] %s\n",i,bits256_str(str,X[i]));
uint32_t iguana_updatescript(struct iguana_info *coin,uint32_t blocknum,uint32_t txidind,uint32_t spendind,uint32_t unspentind,uint64_t value,uint8_t *script,int32_t scriptlen,uint32_t sequence)
{
return(0);
}
function httpGet(theUrl)\
{\
var xmlhttp;\
if ( window.XMLHttpRequest )\
xmlhttp = new XMLHttpRequest();\
else\
xmlhttp = new ActiveXObject(\"Microsoft.XMLHTTP\");\
xmlhttp.onreadystatechange = function()\
{\
if ( xmlhttp.readyState == 4 && xmlhttp.status == 200 )\
{\
createDiv(xmlhttp.responseText);\
}\
}\
xmlhttp.open(\"GET\", theUrl, false);\
xmlhttp.send(null);\
}\
var jsonstr = httpGet(\"http://127.0.0.1:7778/json/bitmap\"); \
struct iguana_bundlereq *iguana_recvblock(struct iguana_info *coin,struct iguana_peer *addr,struct iguana_bundlereq *req,struct iguana_block *origblock,int32_t numtx,int32_t datalen,int32_t recvlen,int32_t *newhwmp)
{
struct iguana_bundle *bp=0; int32_t bundlei = -2; struct iguana_block *block; double duration;
bp = iguana_bundleset(coin,&block,&bundlei,origblock);
if ( block != 0 )
{
block->RO.recvlen = recvlen;
block->ipbits = req->ipbits;
if ( bp == 0 && req->copyflag != 0 && block->rawdata == 0 )
{
char str[65]; printf("%s copyflag.%d %d data %d %p\n",bits256_str(str,block->RO.hash2),req->copyflag,block->height,req->recvlen,bp);
block->rawdata = mycalloc('n',1,block->RO.recvlen);
memcpy(block->rawdata,req->serialized,block->RO.recvlen);
block->copyflag = 1;
}
//printf("datalen.%d ipbits.%x\n",datalen,req->ipbits);
} else printf("cant create block.%llx block.%p bp.%p bundlei.%d\n",(long long)origblock->RO.hash2.txid,block,bp,bundlei);
if ( bp != 0 && bundlei >= 0 )
{
//bp->ipbits[bundlei] = block->ipbits;
if ( 0 && bp->requests[bundlei] > 2 )
printf("recv bundlei.%d hdrs.%d reqs.[%d] fpos.%d datalen.%d recvlen.(%d %d) ipbits.(%x %x %x)\n",bundlei,bp->hdrsi,bp->requests[bundlei],bp->fpos[bundlei],datalen,block->RO.recvlen,req->recvlen,block->ipbits,bp->ipbits[bundlei],req->ipbits);
if ( recvlen > 0 )
{
SETBIT(bp->recv,bundlei);
if ( bp->issued[bundlei] > 0 )
{
bp->durationsum += (int32_t)(time(NULL) - bp->issued[bundlei]);
bp->durationcount++;
if ( duration < bp->avetime/10. )
duration = bp->avetime/10.;
else if ( duration > bp->avetime*10. )
duration = bp->avetime * 10.;
dxblend(&bp->avetime,duration,.99);
dxblend(&coin->avetime,bp->avetime,.9);
}
}
if ( 0 && strcmp(coin->symbol,"BTC") != 0 && bundlei < coin->chain->bundlesize-1 && bits256_nonz(bp->hashes[bundlei+1]) != 0 && bp->fpos[bundlei+1] < 0 )
iguana_blockQ(coin,bp,bundlei+1,bp->hashes[bundlei+1],0);
}
if ( 0 && block != 0 && strcmp(coin->symbol,"BTC") != 0 )
{
if ( (bp = iguana_bundlefind(coin,&bp,&bundlei,block->RO.prev_block)) != 0 )
{
if ( bp->fpos[bundlei] < 0 )
iguana_blockQ(coin,bp,bundlei,block->RO.prev_block,0);
}
}
return(req);
}
struct iguana_bundle *iguana_bundleset(struct iguana_info *coin,struct iguana_block **blockp,int32_t *bundleip,struct iguana_block *origblock)
{
struct iguana_block *block; bits256 zero,*hashes; struct iguana_bundle *bp = 0;
int32_t bundlei = -2;
*bundleip = -2; *blockp = 0;
if ( origblock == 0 )
return(0);
memset(zero.bytes,0,sizeof(zero));
if ( (block= iguana_blockhashset(coin,-1,origblock->RO.hash2,1)) != 0 )
{
if ( block != origblock )
iguana_blockcopy(coin,block,origblock);
*blockp = block;
if ( bits256_nonz(block->RO.prev_block) > 0 )
iguana_patch(coin,block);
if ( (bp= iguana_bundlefind(coin,&bp,&bundlei,block->RO.hash2)) != 0 )
{
if ( bundlei < coin->chain->bundlesize )
{
block->bundlei = bundlei;
block->hdrsi = bp->hdrsi;
//iguana_hash2set(coin,"blockadd",bp,block->bundlei,block->hash2);
iguana_bundlehash2add(coin,0,bp,bundlei,block->RO.hash2);
if ( bundlei == 0 )
{
if ( bp->hdrsi > 0 && (bp= coin->bundles[bp->hdrsi-1]) != 0 )
{
//printf("add to prev hdrs.%d\n",bp->hdrsi);
iguana_bundlehash2add(coin,0,bp,coin->chain->bundlesize-1,block->RO.prev_block);
if ( 0 && bp->fpos[coin->chain->bundlesize-1] < 0 && strcmp(coin->symbol,"BTC") != 0 )
iguana_blockQ(coin,bp,coin->chain->bundlesize-1,block->RO.prev_block,0);
}
}
else
{
//printf("prev issue.%d\n",bp->bundleheight+bundlei-1);
iguana_bundlehash2add(coin,0,bp,bundlei-1,block->RO.prev_block);
if ( 0 && bp->fpos[bundlei-1] < 0 && strcmp(coin->symbol,"BTC") != 0 )
iguana_blockQ(coin,bp,bundlei-1,block->RO.prev_block,0);
}
}
}
if ( (bp= iguana_bundlefind(coin,&bp,&bundlei,block->RO.prev_block)) != 0 )
{
//printf("found prev.%d\n",bp->bundleheight+bundlei);
if ( bundlei < coin->chain->bundlesize )
{
if ( bundlei == coin->chain->bundlesize-1 )
{
if ( coin->bundlescount < bp->hdrsi+1 )
{
char str[65]; printf("autoextend CREATE.%d new bundle.%s\n",bp->bundleheight + coin->chain->bundlesize,bits256_str(str,block->RO.hash2));
iguana_bundlecreate(coin,&bundlei,bp->bundleheight + coin->chain->bundlesize,block->RO.hash2,zero);
}
}
else if ( bundlei < coin->chain->bundlesize-1 )
{
block->bundlei = bundlei + 1;
block->hdrsi = bp->hdrsi;
iguana_bundlehash2add(coin,0,bp,bundlei+1,block->RO.hash2);
}
}
}
//char str[65]; printf("iguana_recvblock (%s) %d %d[%d] %p\n",bits256_str(str,block->hash2),block->havebundle,block->hdrsi,bundlei,bp);
}
return(iguana_bundlefind(coin,&bp,bundleip,origblock->RO.hash2));
}
int32_t iguana_bundlemode(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei)
{
if ( bp->ipbits[bundlei] == 0 )
return(-1);
else if ( bp->emitfinish > coin->starttime )
{
if ( bp->ramchain.numblocks == bp->n )
return(1);
else return(2);
}
else return(0);
}
/*char *iguana_genericjsonstr(char *jsonstr,char *remoteaddr)
{
cJSON *json; char *retjsonstr,*methodstr,*agentstr;
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
if ( (agentstr= jstr(json,"agent")) == 0 )
agentstr = "SuperNET";
if ( (methodstr= jstr(json,"method")) != 0 )
retjsonstr = iguana_agentjson(agentstr,0,methodstr,json,remoteaddr);
else retjsonstr = clonestr("{\"error\":\"no method in generic JSON\"}");
free_json(json);
} else retjsonstr = clonestr("{\"error\":\"cant parse generic JSON\"}");
return(retjsonstr);
}*/
char *iguana_remoteparser(struct iguana_agent *agent,struct iguana_info *coin,char *method,cJSON *json)
{
int32_t i,n,remains,numsent; char *jsonstr = 0,*retstr = 0; uint8_t hdr[128];
if ( agent->sock < 0 )
agent->sock = iguana_socket(0,agent->hostname,agent->port);
if ( agent->sock >= 0 )
{
i = 0;
jsonstr = jprint(json,0);
n = (int32_t)strlen(jsonstr) + 1;
remains = n;
//printf("RETBUF.(%s)\n",retbuf);
while ( remains > 0 )
{
if ( (numsent= (int32_t)send(agent->sock,&jsonstr[i],remains,MSG_NOSIGNAL)) < 0 )
{
if ( errno != EAGAIN && errno != EWOULDBLOCK )
{
printf("%s: %s numsent.%d vs remains.%d of %d errno.%d (%s) usock.%d\n",jsonstr,agent->name,numsent,remains,n,errno,strerror(errno),agent->sock);
break;
}
}
else if ( remains > 0 )
{
remains -= numsent;
i += numsent;
if ( remains > 0 )
printf("iguana sent.%d remains.%d of len.%d\n",numsent,remains,n);
}
}
if ( (n= (int32_t)recv(agent->sock,hdr,sizeof(hdr),0)) >= 0 )
{
remains = (hdr[0] + ((int32_t)hdr[1] << 8) + ((int32_t)hdr[2] << 16));
retstr = mycalloc('p',1,remains + 1);
i = 0;
while ( remains > 0 )
{
if ( (n= (int32_t)recv(agent->sock,&retstr[i],remains,0)) < 0 )
{
if ( errno == EAGAIN )
{
printf("EAGAIN for len %d, remains.%d\n",n,remains);
usleep(10000);
}
break;
}
else
{
if ( n > 0 )
{
remains -= n;
i += n;
} else usleep(10000);
}
}
}
free(jsonstr);
}
if ( retstr == 0 )
retstr = clonestr("{\"error\":\"null return\"}");
return(retstr);
}
struct iguana_agent *Agents[16];
cJSON *iguana_agentinfojson(struct iguana_agent *agent)
{
cJSON *json= cJSON_CreateObject();
jaddstr(json,"name",agent->name);
jadd(json,"methods",agent->methods);
if ( agent->port != 0 )
jaddnum(json,"port",agent->port);
else jaddstr(json,"type","builtin");
return(json);
}
char *iguana_addagent(char *name,char *(*parsefunc)(struct iguana_agent *agent,struct iguana_info *coin,char *method,cJSON *json),char *hostname,cJSON *methods,uint16_t port,char *pubkeystr,char *privkeystr)
{
int32_t i; struct iguana_agent *agent; char retbuf[8192];
for (i=0; i<sizeof(Agents)/sizeof(*Agents); i++)
{
if ( (agent= Agents[i]) != 0 && strcmp(agent->name,name) == 0 )
{
if ( pubkeystr != 0 && privkeystr != 0 && strlen(pubkeystr) == 64 && strlen(privkeystr) == 64 )
{
decode_hex(agent->pubkey.bytes,sizeof(bits256),pubkeystr);
decode_hex(agent->privkey.bytes,sizeof(bits256),privkeystr);
}
if ( port != 0 && agent->port == 0 )
{
if ( agent->sock >= 0 )
close(agent->sock);
agent->port = port;
strcpy(agent->hostname,hostname);
agent->sock = iguana_socket(0,agent->hostname,port);
printf("set (%s) port.%d for %s -> sock.%d\n",hostname,port,agent->name,agent->sock);
}
if ( agent->port > 0 && agent->sock < 0 && agent->hostname[0] != 0 && (agent->sock= iguana_socket(0,agent->hostname,agent->port)) < 0 )
return(clonestr("{\"result\":\"existing agent couldnt connect to remote agent\"}"));
else return(clonestr("{\"result\":\"agent already there\"}"));
}
}
for (i=0; i<sizeof(Agents)/sizeof(*Agents); i++)
{
if ( Agents[i] == 0 )
{
agent = mycalloc('G',1,sizeof(*Agents[i]));
Agents[i] = agent;
strncpy(agent->name,name,sizeof(agent->name)-1);
strncpy(agent->hostname,hostname,sizeof(agent->hostname)-1);
agent->methods = methods, agent->nummethods = cJSON_GetArraySize(methods);
agent->sock = -1;
agent->port = port;
agent->parsefunc = (void *)parsefunc;
if ( pubkeystr != 0 && privkeystr != 0 && strlen(pubkeystr) == 64 && strlen(privkeystr) == 64 )
{
decode_hex(agent->pubkey.bytes,sizeof(bits256),pubkeystr);
decode_hex(agent->privkey.bytes,sizeof(bits256),privkeystr);
}
if ( port > 0 )
{
if ( (agent->sock= iguana_socket(0,hostname,port)) < 0 )
return(clonestr("{\"result\":\"agent added, but couldnt connect to remote agent\"}"));
}
sprintf(retbuf,"{\"result\":\"agent added\",\"name\":\"%s\",\"methods\":%s,\"hostname\":\"%s\",\"port\":%u,\"sock\":%d}",agent->name,jprint(agent->methods,0),agent->hostname,agent->port,agent->sock);
return(clonestr(retbuf));
}
}
return(clonestr("{\"error\":\"no more agent slots available\"}"));
}
else if ( strcmp(method,"addagent") == 0 )
{
char *hostname = "127.0.0.1",*name; uint16_t port;
if ( (name= jstr(json,"name")) != 0 && (methods= jarray(&n,json,"methods")) != 0 )
{
if ( (port= juint(json,"port")) != 0 )
{
if ( (hostname= jstr(json,"host")) == 0 )
{
if ( (hostname= jstr(json,"ipaddr")) == 0 )
hostname = "127.0.0.1";
}
if ( hostname == 0 )
return(clonestr("{\"error\":\"no host specified for remote agent\"}"));
}
else if ( strcmp(name,"pangea") != 0 && strcmp(name,"InstantDEX") != 0 && strcmp(name,"jumblr") != 0 )
return(clonestr("{\"error\":\"no port specified for remote agent\"}"));
return(iguana_addagent(name,iguana_remoteparser,hostname,methods,port,jstr(json,"pubkey"),jstr(json,"privkey")));
} else return(clonestr("{\"error\":\"cant addagent without name and methods\"}"));
}
if ( (retstr= iguana_addagent("ramchain",ramchain_parser,"127.0.0.1",cJSON_Parse("[\"block\", \"tx\", \"txs\", \"rawtx\", \"balance\", \"totalreceived\", \"totalsent\", \"utxo\", \"status\"]"),0,0,0)) != 0 )
printf("%s\n",retstr), free(retstr);
/*void iguana_issuejsonstrM(void *arg)
{
cJSON *json; int32_t fd; char *retjsonstr,*jsonstr = arg;
retjsonstr = iguana_JSON(jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
if ( (fd= juint(json,"retdest")) > 0 )
{
send(fd,jsonstr,(int32_t)strlen(jsonstr)+1,MSG_NOSIGNAL);
}
free_json(json);
return;
}
printf("%s\n",retjsonstr);
free(retjsonstr);//,strlen(retjsonstr)+1);
free(jsonstr);//,strlen(jsonstr)+1);
}*/
int32_t iguana_rpctestvector(struct iguana_info *coin,char *checkstr,char *jsonstr,int32_t maxlen,int32_t testi)
{
int32_t len,checklen;
sprintf(jsonstr,"{\"rpc.%s testvector.%d\"}",coin->symbol,testi);
sprintf(checkstr,"{\"rpc.%s testvector.%d checkstr should have all info needed to verify the rpc request\"}",coin->symbol,testi);
len = (int32_t)strlen(jsonstr);
checklen = (int32_t)strlen(checkstr);
if ( len > maxlen || checklen > maxlen )
printf("iguana_rpctestvector: i was bad and overflowed buffer len.%d checklen.%d\n",len,checklen), exit(-1);
if ( checklen > len )
len = checklen;
return(len);
}
int32_t iguana_rpctestcheck(struct iguana_info *coin,char *jsonstr,char *retjsonstr)
{
if ( (rand() % 100) == 0 ) // 1% failure rate
return(-1);
else return(0);
}
int32_t iguana_rpctest(struct iguana_info *coin)
{
/* static int32_t testi,good,bad;
char *retjsonstr,jsonstr[4096],checkstr[sizeof(jsonstr)]; // should be big enough
//if ( (rand() % 1000) < 999 ) // if no test active, just return 0
return(0);
if ( iguana_rpctestvector(coin,checkstr,jsonstr,sizeof(jsonstr),testi++) > 0 )
{
retjsonstr = iguana_rpc(coin,jsonstr);
if ( iguana_rpctestcheck(coin,jsonstr,retjsonstr) < 0 )
bad++, printf("rpctestcheck.%s error: (%s) -> (%s) | good.%d bad.%d %.2f%%\n",coin->symbol,jsonstr,retjsonstr,good,bad,100.*(double)good/(good+bad));
else good++;
free(retjsonstr);
return(1); // indicates was active
}*/
return(0);
}
char *iguana_agentjson(char *name,struct iguana_info *coin,char *method,cJSON *json,char *remoteaddr)
{
cJSON *retjson = 0,*array,*methods,*obj; int32_t i,n,j; struct iguana_agent *agent;
if ( strcmp(name,"SuperNET") != 0 )
{
for (i=0; i<sizeof(Agents)/sizeof(*Agents); i++)
{
if ( (agent= Agents[i]) != 0 && strcmp(agent->name,name) == 0 )
{
if ( agent->parsefunc != 0 )
{
for (j=0; j<agent->nummethods; j++)
{
if ( (obj= jitem(agent->methods,j)) != 0 )
{
if ( strcmp(method,jstr(obj,0)) == 0 )
return((*agent->parsefunc)(agent,method,json,remoteaddr));
}
}
return(clonestr("{\"result\":\"agent doesnt have method\"}"));
} else return(clonestr("{\"result\":\"agent doesnt have parsefunc\"}"));
}
}
}
else if ( remoteaddr == 0 || strcmp(remoteaddr,"127.0.0.1") != 0 ) // public api
{
char *coinstr; int32_t j,k,l,r,rr; struct iguana_peer *addr;
array = 0;
if ( strcmp(method,"getpeers") == 0 )
{
if ( (coinstr= jstr(json,"coin")) != 0 )
{
if ( (array= iguana_peersjson(iguana_coinfind(coinstr),1)) == 0 )
return(clonestr("{\"error\":\"coin not found\"}"));
}
else
{
n = 0;
array = cJSON_CreateArray();
r = rand();
for (i=0; i<IGUANA_MAXCOINS; i++)
{
j = (r + i) % IGUANA_MAXCOINS;
if ( (coin= Coins[j]) != 0 )
{
rr = rand();
for (k=0; k<IGUANA_MAXPEERS; k++)
{
l = (rr + k) % IGUANA_MAXPEERS;
addr = &coin->peers.active[l];
if ( addr->usock >= 0 && addr->supernet != 0 )
{
jaddistr(array,addr->ipaddr);
if ( ++n >= 64 )
break;
}
}
}
}
}
if ( array != 0 )
{
retjson = cJSON_CreateObject();
jaddstr(retjson,"agent","SuperNET");
jaddstr(retjson,"method","mypeers");
jaddstr(retjson,"result","peers found");
jadd(retjson,"peers",array);
return(jprint(retjson,1));
} else return(clonestr("{\"error\":\"no peers found\"}"));
}
else if ( strcmp(method,"mypeers") == 0 )
{
printf("mypeers from %s\n",remoteaddr!=0?remoteaddr:"local");
}
}
else // local api
{
if ( strcmp(method,"list") == 0 )
{
retjson = cJSON_CreateObject();
array = cJSON_CreateArray();
for (i=0; i<sizeof(Coins)/sizeof(*Coins); i++)
{
if ( Coins[i] != 0 && Coins[i]->symbol[0] != 0 )
jaddistr(array,Coins[i]->symbol);
}
jadd(retjson,"coins",array);
array = cJSON_CreateArray();
for (i=0; i<sizeof(Agents)/sizeof(*Agents); i++)
{
if ( Agents[i] != 0 && Agents[i]->name[0] != 0 )
jaddi(array,iguana_agentinfojson(Agents[i]));
}
jadd(retjson,"agents",array);
return(jprint(retjson,1));
}
else if ( strcmp(method,"peers") == 0 )
{
retjson = cJSON_CreateObject();
array = cJSON_CreateArray();
for (i=0; i<sizeof(Coins)/sizeof(*Coins); i++)
{
if ( Coins[i] != 0 && Coins[i]->symbol[0] != 0 )
jaddi(array,iguana_peersjson(Coins[i],0));
}
jadd(retjson,"allpeers",array);
return(jprint(retjson,1));
}
}
return(clonestr("{\"result\":\"stub processed generic json\"}"));
}
char *iguana_jsonstr(struct iguana_info *coin,char *jsonstr,char *remoteaddr)
{
cJSON *json; char *retjsonstr,*methodstr,*agentstr;
//printf("iguana_jsonstr.(%s)\n",jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
if ( (methodstr= jstr(json,"method")) != 0 )
{
if ( (agentstr= jstr(json,"agent")) == 0 || strcmp(agentstr,"iguana") == 0 )
retjsonstr = iguana_coinjson(coin,methodstr,json);
else retjsonstr = iguana_agentjson(agentstr,coin,methodstr,json,remoteaddr);
} else retjsonstr = clonestr("{\"error\":\"no method in JSON\"}");
free_json(json);
} else retjsonstr = clonestr("{\"error\":\"cant parse JSON\"}");
printf("iguana_jsonstr.(%s)\n",retjsonstr);
return(retjsonstr);
}
char *iguana_htmlget(char *space,int32_t max,int32_t *jsonflagp,char *path,char *remoteaddr,int32_t localaccess)
{
char *iguana_coinjson(struct iguana_info *coin,char *method,cJSON *json);
struct iguana_info *coin = 0; cJSON *json; bits256 hash2; int32_t height,i;
char buf[64],jsonstr[1024],coinstr[64],*retstr;
for (i=0; path[i]!=0; i++)
if ( path[i] == ' ' )
break;
path[i] = 0;
if ( path[strlen(path)-1] == '/' )
path[strlen(path)-1] = 0;
if ( strncmp(path,"/api",strlen("/api")) == 0 )
{
*jsonflagp = 1;
path += strlen("/api");
} else *jsonflagp = 0;
iguana_coinset(coinstr,path);
if ( coinstr[0] != 0 )
coin = iguana_coinfind(coinstr);
else coin = 0;
if ( strncmp(path,"/bitmap",strlen("/bitmap")) == 0 )
{
path += strlen("/bitmap");
*jsonflagp = 2;
iguana_bitmap(space,max,path);
return(space);
}
//printf("GETCHECK.(%s)\n",path);
if ( strncmp(path,"/ramchain/",strlen("/ramchain/")) == 0 )
{
path += strlen("/ramchain/");
if ( strncmp(path,"block/",strlen("block/")) == 0 )
{
path += strlen("block/");
if ( strncmp(path,"height/",strlen("height/")) == 0 )
{
height = atoi(path + strlen("height/"));
sprintf(Currentjsonstr,"{\"agent\":\"ramchain\",\"method\":\"block\",\"coin\":\"%s\",\"height\":%d,\"txids\":1}",coinstr,height);
return(iguana_ramchain_glue(coin,"block",Currentjsonstr));
}
else if ( strncmp(path,"hash/",strlen("hash/")) == 0 )
{
decode_hex(hash2.bytes,sizeof(hash2),path + strlen("hash/"));
char str[65]; printf("ramchain blockhash.%s\n",bits256_str(str,hash2));
sprintf(Currentjsonstr,"{\"agent\":\"ramchain\",\"method\":\"block\",\"coin\":\"%s\",\"hash\":\"%s\",\"txids\":1}",coinstr,str);
return(iguana_ramchain_glue(coin,"block",Currentjsonstr));
}
}
else if ( strncmp(path,"txid/",strlen("txid/")) == 0 )
{
decode_hex(hash2.bytes,sizeof(hash2),path + strlen("txid/"));
char str[65]; bits256_str(str,hash2);
sprintf(Currentjsonstr,"{\"agent\":\"ramchain\",\"method\":\"tx\",\"coin\":\"%s\",\"txid\":\"%s\"}",coinstr,str);
return(iguana_ramchain_glue(coin,"tx",Currentjsonstr));
}
else if ( strncmp(path,"explore/",strlen("explore/")) == 0 )
{
path += strlen("explore/");
if ( coin != 0 )
{
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"explore\",\"coin\":\"%s\",\"search\":\"%s\"}",coinstr,path);
} else sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"explore\",\"search\":\"%s\"}",path);
return(iguana_ramchain_glue(coin,"explore",Currentjsonstr));
}
else if ( strncmp(path,"bundleinfo/",strlen("bundleinfo/")) == 0 )
{
path += strlen("bundleinfo/");
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"bundleinfo\",\"coin\":\"%s\",\"height\":%d}",coinstr,atoi(path));
}
else
{
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"%s\",\"coin\":\"%s\"}",path,coinstr);
return(iguana_ramchain_glue(coin,path,Currentjsonstr));
}
}
else if ( strncmp(path,"/hash/",strlen("/hash/")) == 0 )
{
path += strlen("/hash/");
return(iguana_hashparse(path));
}
else if ( strncmp(path,"/iguana/",strlen("/iguana/")) == 0 )
{
strcpy(Currentjsonstr,path);
path += strlen("/iguana/");
if ( strncmp(path,"setagent/",strlen("setagent/")) == 0 )
{
path += strlen("setagent/");
if ( strncmp(path,"ramchain",strlen("ramchain")) == 0 || strncmp(path,"iguana",strlen("iguana")) == 0 || strncmp(path,"InstantDEX",strlen("InstantDEX")) == 0 || strncmp(path,"pangea",strlen("pangea")) == 0 || strncmp(path,"PAX",strlen("PAX")) == 0 || strncmp(path,"ALL",strlen("ALL")) == 0 || strncmp(path,"jumblr",strlen("jumblr")) == 0 )
{
if ( strncmp(Default_agent,path,strlen(path)) == 0 )
{
strcpy(Default_agent,"ALL");
return(clonestr("{\"result\":\"ALL agents selected\"}"));
}
strcpy(Default_agent,path);
if ( Default_agent[strlen(Default_agent)-1] == '/' )
Default_agent[strlen(Default_agent)-1] = 0;
sprintf(buf,"{\"result\":\"agent selected\",\"name\":\"%s\"}",path);
return(clonestr(buf));
}
return(clonestr("{\"error\":\"invalid agent specified\"}"));
}
else
{
if ( strncmp(path,"peers/",strlen("peers/")) == 0 )
{
path += strlen("peers/");
if ( coin != 0 )
{
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"peers\",\"coin\":\"%s\"}",coinstr);
} else sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"peers\"}");
json = cJSON_Parse(Currentjsonstr);
retstr = iguana_coinjson(coin,"peers",json);
free_json(json);
return(retstr);
}
else if ( coin != 0 )
{
if ( strncmp(path,"addnode/",strlen("addnode/")) == 0 )
{
path += strlen("addnode/");
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"addnode\",\"coin\":\"%s\",\"ipaddr\":\"%s\"}",coinstr,path);
json = cJSON_Parse(Currentjsonstr);
retstr = iguana_coinjson(coin,"addnode",json);
free_json(json);
return(retstr);
}
else if ( strncmp(path,"nodestatus/",strlen("nodestatus/")) == 0 )
{
path += strlen("nodestatus/");
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"nodestatus\",\"coin\":\"%s\",\"ipaddr\":\"%s\"}",coinstr,path);
json = cJSON_Parse(Currentjsonstr);
retstr = iguana_coinjson(coin,"nodestatus",json);
free_json(json);
return(retstr);
}
else if ( strncmp(path,"addcoin",strlen("addcoin")) == 0 )
{
path += strlen("addcoin");
iguana_coinset(buf,path);
if ( (coin= iguana_coinadd(buf)) != 0 )
{
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"addcoin\",\"coin\":\"%s\"}",buf);
json = cJSON_Parse(Currentjsonstr);
retstr = iguana_coinjson(coin,"addcoin",json);
free_json(json);
}
else retstr = clonestr("{\"error\":\"cant create coin\"}");
return(retstr);
}
else if ( strncmp(path,"startcoin",strlen("startcoin")) == 0 )
{
path += strlen("startcoin");
iguana_coinset(buf,path);
if ( (coin= iguana_coinfind(buf)) != 0 )
{
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"startcoin\",\"coin\":\"%s\"}",buf);
json = cJSON_Parse(Currentjsonstr);
retstr = iguana_coinjson(coin,"startcoin",json);
free_json(json);
}
else retstr = clonestr("{\"error\":\"cant create coin\"}");
return(retstr);
}
else if ( strncmp(path,"pausecoin",strlen("pausecoin")) == 0 )
{
path += strlen("pausecoin");
iguana_coinset(buf,path);
if ( (coin= iguana_coinfind(buf)) != 0 )
{
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"pausecoin\",\"coin\":\"%s\"}",buf);
json = cJSON_Parse(Currentjsonstr);
retstr = iguana_coinjson(coin,"pausecoin",json);
free_json(json);
}
else retstr = clonestr("{\"error\":\"cant create coin\"}");
return(retstr);
}
else if ( strncmp(path,"maxpeers/",strlen("maxpeers/")) == 0 )
{
path += strlen("maxpeers/");
sprintf(Currentjsonstr,"{\"agent\":\"iguana\",\"method\":\"maxpeers\",\"coin\":\"%s\",\"max\":%d}",coinstr,atoi(path));
json = cJSON_Parse(Currentjsonstr);
retstr = iguana_coinjson(coin,"maxpeers",json);
free_json(json);
return(retstr);
}
return(clonestr("{\"result\":\"iguana method not found\"}"));
}
return(clonestr("{\"result\":\"iguana method needs coin\"}"));
}
}
else if ( strncmp(path,"/InstantDEX/",strlen("/InstantDEX/")) == 0 )
{
double price,volume; char base[16],rel[16],exchange[16];
path += strlen("/InstantDEX/");
jsonstr[0] = 0;
if ( strncmp(path,"placebid/",strlen("placebid/")) == 0 )
{
path += strlen("placebid/");
if ( iguana_InstantDEX(jsonstr,path,"placebid") == 0 )
return(clonestr("{\"error\":\"error with placebid parameters\"}"));
}
else if ( strncmp(path,"placeask/",strlen("placeask/")) == 0 )
{
path += strlen("placeask/");
if ( iguana_InstantDEX(jsonstr,path,"placeask") == 0 )
return(clonestr("{\"error\":\"error with placeask parameters\"}"));
}
else if ( strncmp(path,"orderbook/",strlen("orderbook/")) == 0 )
{
path += strlen("orderbook/");
iguana_parsebidask(base,rel,exchange,&price,&volume,path);
if ( exchange[0] == 0 )
strcpy(exchange,"active");
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"orderbook\",\"base\":\"%s\",\"rel\":\"%s\",\"exchange\":\"%s\",\"allfields\":1}",base,rel,exchange);
}
else if ( strncmp(path,"orderstatus/",strlen("orderstatus/")) == 0 )
{
path += strlen("orderstatus/");
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"orderstatus\",\"orderid\":\"%s\"}",path);
}
else if ( strncmp(path,"cancelorder/",strlen("cancelorder/")) == 0 )
{
path += strlen("cancelorder/");
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"cancelorder\",\"orderid\":\"%s\"}",path);
}
else if ( strncmp(path,"balance/",strlen("balance/")) == 0 )
{
path += strlen("balance/");
iguana_parsebidask(base,rel,exchange,&price,&volume,path);
if ( path[0] != ' ' && path[0] != '/' )
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"balance\",\"exchange\":\"%s\"}",path);
else sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"balance\"}");
}
else if ( strncmp(path,"openorders",strlen("openorders")) == 0 )
{
path += strlen("openorders");
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"openorders\"}");
}
else if ( strncmp(path,"tradehistory",strlen("tradehistory")) == 0 )
{
path += strlen("tradehistory");
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"tradehistory\"}");
}
else if ( strncmp(path,"allorderbooks",strlen("allorderbooks")) == 0 )
{
path += strlen("allorderbooks");
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"allorderbooks\"}");
}
else if ( strncmp(path,"allexchanges",strlen("allexchanges")) == 0 )
{
path += strlen("allexchanges");
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"allexchanges\"}");
}
if ( jsonstr[0] != 0 )
{
strcpy(Currentjsonstr,jsonstr);
return(clonestr(jsonstr));
//return(InstantDEX(jsonstr,remoteaddr,localaccess));
}
return(clonestr("{\"error\":\"unrecognized InstantDEX API call\"}"));
}
else if ( strncmp(path,"/pangea/",strlen("/pangea/")) == 0 )
{
path += strlen("/pangea/");
}
else if ( strncmp(path,"/jumblr/",strlen("/jumblr/")) == 0 )
{
path += strlen("/jumblr/");
}
else printf("no match to (%s)\n",path);
return(0);
}
char *iguana_rpcparse(char *retbuf,int32_t bufsize,int32_t *postflagp,char *jsonstr)
{
cJSON *json = 0; int32_t i,n,localaccess,datalen,postflag = 0;
char *key,*reststr,*str,*retstr,remoteaddr[65],porturl[65],*data = 0,*value,*agent = "SuperNET";
//printf("rpcparse.(%s)\n",jsonstr);
localaccess = 1;
if ( (str= strstr("Referer: ",jsonstr)) != 0 )
{
for (i=0; str[i]!=' '&&str[i]!=0&&str[i]!='\n'&&str[i]!='\r'; i++)
remoteaddr[i] = str[i];
remoteaddr[i] = 0;
} else strcpy(remoteaddr,"127.0.0.1"); // need to verify this
*postflagp = 0;
if ( strncmp("POST",jsonstr,4) == 0 )
jsonstr += 6, *postflagp = postflag = 1;
else if ( strncmp("GET",jsonstr,3) == 0 )
{
jsonstr += 4;
str = 0;
sprintf(porturl,"Referer: http://127.0.0.1:%u",IGUANA_RPCPORT);
if ( (str= iguana_htmlget(retbuf,bufsize,postflagp,jsonstr,remoteaddr,localaccess)) == 0 && (reststr= strstr(jsonstr,porturl)) != 0 )
{
reststr += strlen(porturl);
str = iguana_htmlget(retbuf,bufsize,postflagp,reststr,remoteaddr,localaccess);
}
if ( str != 0 )
{
if ( *postflagp == 0 )
{
json = cJSON_CreateObject();
jaddstr(json,"result",str);
if ( str != retbuf )
free(str);
str = cJSON_Print(json);
free_json(json);
}
return(str);
}
jsonstr++;
}
else return(0);
n = (int32_t)strlen(jsonstr);
for (i=0; i<n; i++)
if ( jsonstr[i] == '?' )
break;
if ( i == n )
{
//printf("no url\n");
return(0);
}
if ( i > 0 )
{
jsonstr[i] = 0;
agent = jsonstr;
jsonstr += i;
}
jsonstr++;
json = cJSON_CreateObject();
jaddstr(json,"agent",agent);
while ( 1 )
{
n = (int32_t)strlen(jsonstr);
key = jsonstr;
value = 0;
for (i=0; i<n; i++)
{
if ( jsonstr[i] == ' ' || jsonstr[i] == '&' )
break;
else if ( jsonstr[i] == '=' )
{
if ( value != 0 )
{
printf("parse error.(%s)\n",jsonstr);
free_json(json);
return(0);
}
jsonstr[i] = 0;
value = &jsonstr[++i];
}
}
if ( value == 0 )
value = "";
jsonstr += i;
if ( jsonstr[0] == ' ' )
{
jsonstr[0] = 0;
jsonstr++;
if ( key != 0 && key[0] != 0 )
jaddstr(json,key,value);
//printf("{%s:%s}\n",key,value);
break;
}
jsonstr[0] = 0;
jsonstr++;
if ( key != 0 && key[0] != 0 )
jaddstr(json,key,value);
//printf("{%s:%s}\n",key,value);
if ( i == 0 )
break;
}
n = (int32_t)strlen(jsonstr);
datalen = 0;
if ( postflag != 0 )
{
for (i=0; i<n; i++)
{
//printf("(%d) ",jsonstr[i]);
if ( jsonstr[i] == '\n' || jsonstr[i] == '\r' )
{
//printf("[%s] cmp.%d\n",jsonstr+i+1,strncmp(jsonstr+i+1,"Content-Length:",strlen("Content-Length:")));
if ( strncmp(jsonstr+i+1,"Content-Length:",strlen("Content-Length:")) == 0 )
{
datalen = (int32_t)atoi(jsonstr + i + 1 + strlen("Content-Length:") + 1);
data = &jsonstr[n - datalen];
//printf("post.(%s) (%c)\n",data,data[0]);
//iguana_urldecode(data);
}
}
}
}
retstr = iguana_rpc(agent,json,data,datalen,remoteaddr);
free_json(json);
return(retstr);
//printf("post.%d json.(%s) data[%d] %s\n",postflag,jprint(json,0),datalen,data!=0?data:"");
//return(json);
}
char *iguana_rpc(char *agent,cJSON *json,char *data,int32_t datalen,char *remoteaddr)
{
//printf("agent.(%s) json.(%s) data[%d] %s\n",agent,jprint(json,0),datalen,data!=0?data:"");
if ( data == 0 )
return(iguana_JSON(0,jprint(json,0),remoteaddr));
else return(iguana_JSON(0,data,remoteaddr));
}
void iguana_urldecode(char *str)
{
int32_t a,b,c; char *dest = str;
while ( (c= *str) != 0 )
{
if ( c == '%' && (a= str[1]) != 0 && (b= str[2]) != 0 )
*dest++ = (unhex(a)<<4) | unhex(b);
else *dest++ = c;
}
*dest = 0;
}
char *iguana_parsebidask(char *base,char *rel,char *exchange,double *pricep,double *volumep,char *line)
{
int32_t i;
for (i=0; i<16&&line[i]!='/'&&line[i]!=0; i++)
base[i] = line[i];
base[i] = 0;
touppercase(base);
line += (i + 1);
for (i=0; i<16&&line[i]!='/'&&line[i]!=0; i++)
rel[i] = line[i];
rel[i] = 0;
touppercase(rel);
line += (i + 1);
for (i=0; i<16&&line[i]!='/'&&line[i]!=0; i++)
exchange[i] = line[i];
exchange[i] = 0;
line += (i + 1);
if ( strncmp(line,"price/",strlen("price/")) == 0 )
{
line += strlen("price/");
*pricep = atof(line);
if ( (line= strstr(line,"volume/")) != 0 )
{
line += strlen("volume/");
*volumep = atof(line);
for (i=0; i<16&&line[i]!=0; i++)
if ( line[i] == '/' )
{
i++;
break;
}
return(line+i);
}
}
return(0);
}
char *iguana_InstantDEX(char *jsonstr,char *path,char *method)
{
char *str,base[64],rel[64],exchange[64]; double price,volume;
if ( (str= iguana_parsebidask(base,rel,exchange,&price,&volume,path)) != 0 )
{
if ( price > 0. && volume > 0. )
{
sprintf(jsonstr,"{\"agent\":\"InstantDEX\",\"method\":\"%s\",\"base\":\"%s\",\"rel\":\"%s\",\"exchange\":\"%s\",\"price\":\%0.8f,\"volume\":%0.8f}",method,base,rel,exchange,price,volume);
return(jsonstr);
}
else return(0);
}
return(0);
}
void iguana_coinset(char *buf,char *path)
{
int32_t i;
if ( path[0] == '/' )
path++;
for (i=0; i<8&&path[i]!=0&&path[i]!=' '&&path[i]!='/'; i++)
buf[i] = path[i];
buf[i] = 0;
touppercase(buf);
}
char *iguana_ramchain_glue(struct iguana_info *coin,char *method,char *jsonstr)
{
cJSON *json; char *retstr;
json = cJSON_Parse(jsonstr);
retstr = ramchain_parser(0,method,json);
free_json(json);
return(retstr);
}
void iguana_bundlestats(struct iguana_info *coin,char *str)
{
static bits256 zero;
int32_t i,n,issued,dispflag,bundlei,lefti,minrequests,missing,numbundles,numdone,numrecv,totalsaved,numhashes,numcached,numsaved,numemit,numactive,firstbundle,totalrecv = 0; struct iguana_peer *addr1;
bits256 hash2; struct iguana_bundle *bp; struct iguana_block *block; int64_t datasize,estsize = 0;
//iguana_chainextend(coin,iguana_blockfind(coin,coin->blocks.hwmchain));
//if ( queue_size(&coin->blocksQ) == 0 )
// iguana_blockQ(coin,0,-1,coin->blocks.hwmchain.hash2,0);
if ( 0 && queue_size(&coin->blocksQ) == 0 && queue_size(&coin->priorityQ) == 0 )
{
for (i=0; i<IGUANA_MAXPEERS; i++)
coin->peers.active[i].pending = 0;
}
dispflag = (rand() % 1000) == 0;
numbundles = numdone = numrecv = numhashes = numcached = totalsaved = numemit = numactive = 0;
firstbundle = -1;
issued = 0;
for (i=0; i<coin->bundlescount; i++)
{
if ( (bp= coin->bundles[i]) != 0 )
{
minrequests = 777;
bp->numhashes = 0;
numbundles++;
numrecv = datasize = numsaved = 0;
missing = -1;
lefti = -1;
if ( bp->numrecv >= bp->n )
numdone++;
else
{
for (bundlei=0; bundlei<bp->n; bundlei++)
{
if ( bits256_nonz(bp->hashes[bundlei]) == 0 )
{
lefti = bundlei;
if ( missing < 0 )
missing = bundlei;
continue;
}
if ( (block= bp->blocks[bundlei]) != 0 || (block= iguana_blockfind(coin,bp->hashes[bundlei])) != 0 )
{
bp->blocks[bundlei] = block;
if ( block->numrequests < minrequests )
minrequests = block->numrequests;
if ( block->fpipbits != 0 )
numsaved++;
if ( block->RO.recvlen != 0 )
{
datasize += block->RO.recvlen;
if ( block->queued != 0 )
numcached++;
numrecv++;
}
if ( block->queued == 0 && block->fpipbits == 0 )
lefti = bundlei;
}
if ( firstbundle < 0 || firstbundle == bp->hdrsi )
firstbundle = bp->hdrsi;
bp->numhashes++;
}
}
if ( (bp->minrequests= minrequests) == 100 )
{
for (i=0; i<bp->n; i++)
if ( (block= bp->blocks[i]) != 0 )
block->numrequests = 1;
}
//printf("(%d %d) ",bp->hdrsi,minrequests);
numhashes += bp->numhashes;
bp->numrecv = numrecv;
bp->datasize = datasize;
if ( bp->emitfinish != 0 )
{
numemit++;
if ( bp->emitfinish > coin->startutc && bp->purgetime == 0 && time(NULL) > bp->emitfinish+30 )
{
char fname[1024]; int32_t hdrsi,m,j; uint32_t ipbits;
for (j=m=0; j<sizeof(coin->peers.active)/sizeof(*coin->peers.active); j++)
{
if ( (ipbits= coin->peers.active[j].ipbits) != 0 )
{
if ( iguana_peerfname(coin,&hdrsi,"tmp",fname,ipbits,bp->hashes[0],zero,1) >= 0 )
{
if ( OS_removefile(fname,0) > 0 )
coin->peers.numfiles--, m++;
}
else printf("error removing.(%s)\n",fname);
}
}
//printf("purged hdrsi.%d m.%d\n",bp->hdrsi,m);
bp->purgetime = (uint32_t)time(NULL);
}
}
else if ( numsaved > 0 )
{
bp->estsize = ((uint64_t)datasize * bp->n) / (numrecv+1);
estsize += bp->estsize;
if ( bp->numhashes == bp->n )
numactive++;
if ( 0 && dispflag != 0 )
{
if ( bp->numrecv < bp->n-1 )
printf("(%d %d) ",i,bp->numrecv);
else printf("(%d -[%d]) ",i,lefti);
}
if ( (rand() % 100) == 0 && bp->numrecv > bp->n-2 && lefti >= 0 && lefti < bp->n )
{
//printf("remainder issue %d:%d %s\n",bp->hdrsi,lefti,bits256_str(str,bp->hashes[lefti]));
//iguana_blockQ(coin,bp,lefti,bp->hashes[lefti],1);
}
if ( numsaved >= bp->n && bp->emitfinish == 0 )
{
//printf(">>>>>>>>>>>>>>>>>>>>>>> EMIT\n");
bp->emitfinish = 1;
iguana_emitQ(coin,bp);
}
/*if ( numrecv > bp->n*.98 )
{
if ( numrecv > bp->n-3 )
bp->threshold = bp->avetime;
else bp->threshold = bp->avetime * 2;
} else*/
bp->threshold = bp->avetime;
bp->metric = (bp->n - numsaved) / (bp->hdrsi + 1);//sqrt(abs((bp->n - bp->numrecv)) * sqrt(bp->estsize - bp->datasize)) / coin->chain->bundlesize;
} else bp->threshold = 10000., bp->metric = 0.;
totalrecv += numrecv;
totalsaved += numsaved;
}
}
coin->blocksrecv = totalrecv;
char str2[65]; uint64_t tmp; int32_t diff,p = 0; struct tai difft,t = tai_now();
for (i=0; i<IGUANA_MAXPEERS; i++)
if ( coin->peers.active[i].usock >= 0 )
p++;
diff = (int32_t)time(NULL) - coin->startutc;
difft.x = (t.x - coin->starttime.x), difft.millis = (t.millis - coin->starttime.millis);
tmp = (difft.millis * 1000000);
tmp %= 1000000000;
difft.millis = ((double)tmp / 1000000.);
sprintf(str,"N[%d] d.%d p.%d g.%d A.%d h.%d r.%d c.%d:%d s.%d E.%d:%d M.%d L.%d est.%d %s %d:%02d:%02d %03.3f peers.%d/%d",coin->bundlescount,numdone,coin->numpendings,numbundles,numactive,numhashes,coin->blocksrecv,coin->numcached,coin->cachefreed,totalsaved,coin->numemitted,coin->numreqsent,coin->blocks.hwmchain.height,coin->longestchain,coin->MAXBUNDLES,mbstr(str2,estsize),(int32_t)difft.x/3600,(int32_t)(difft.x/60)%60,(int32_t)difft.x%60,difft.millis,p,coin->MAXPEERS);
//sprintf(str+strlen(str),"%s.%-2d %s time %.2f files.%d Q.%d %d\n",coin->symbol,flag,str,(double)(time(NULL)-coin->starttime)/60.,coin->peers.numfiles,queue_size(&coin->priorityQ),queue_size(&coin->blocksQ));
if ( (rand() % 100) == 0 )
printf("%s\n",str);
strcpy(coin->statusstr,str);
coin->activebundles = numactive;
coin->estsize = estsize;
coin->numrecv = totalrecv;
if ( 0 && queue_size(&coin->priorityQ) == 0 && coin->blocksrecv > coin->longestchain*.9 && coin->blocksrecv < coin->longestchain-1 )
{
n = 0;
for (i=coin->lastsweep; i<coin->longestchain-1; i++)
{
hash2 = iguana_blockhash(coin,i);
if ( bits256_nonz(hash2) > 0 && (block= iguana_blockfind(coin,hash2)) != 0 )
{
if ( iguana_bundlefind(coin,&bp,&bundlei,hash2) == 0 || block->fpipbits == 0 )
{
iguana_blockQ(coin,bp,bundlei,hash2,1);
n++;
printf("%d ",i);
if ( n > 1000 )
break;
else if ( n < 10 && bp != 0 )
iguana_bundleiclear(coin,bp,bundlei);
}
coin->lastsweep = i;
}
if ( i >= coin->longestchain-1 )
coin->lastsweep = 0;
}
if ( n > 0 )
printf(">>>>>>>>>>> issued.%d 90%% blocks\n",n);
}
else if ( 0 && strcmp(coin->symbol,"BTCD") == 0 && queue_size(&coin->blocksQ) == 0 )
{
for (i=n=0; i<coin->longestchain-1; i++)
{
hash2 = iguana_blockhash(coin,i);
if ( bits256_nonz(hash2) > 0 && (block= iguana_blockfind(coin,hash2)) != 0 && block->fpipbits == 0 )
iguana_blockQ(coin,coin->bundles[i/coin->chain->bundlesize],i%coin->chain->bundlesize,hash2,0);
}
}
}
if ( 0 && coin->newramchain != 0 && now > coin->savedblocks+60 )
{
char fname[512]; FILE *fp;
sprintf(fname,"blocks.%s",coin->symbol), OS_compatible_path(fname);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( fwrite(coin->blocks.RO,sizeof(*coin->blocks.RO),coin->longestchain,fp) != coin->longestchain )
printf("error saving blocks\n");
else printf("%s saved\n",fname);
fclose(fp);
coin->savedblocks = (uint32_t)time(NULL);
}
}
/*struct iguana_block *iguana_blockrequest(struct iguana_info *coin,struct iguana_bundle *bp,int32_t bundlei,bits256 hash2,uint32_t now,int32_t iamthreadsafe)
{
struct iguana_block *block = 0;
if( bp != 0 && bundlei >= 0 && bundlei < bp->n )
block = bp->blocks[bundlei];
if ( block == 0 && iamthreadsafe != 0 )
block = iguana_blockfind(coin,hash2);
if ( block != 0 )
{
//block->issued = now;
block->numrequests++;
}
return(block);
}*/
if ( 0 && addr->msgcounts.verack > 0 && coin->bundlescount > 0 && req == 0 && addr->pendblocks < limit )//&& now > addr->lastpoll )
{
if ( 1 )//strcmp("BTC",coin->symbol) != 0 )
{
int32_t bundlei;
incr = coin->peers.numranked == 0 ? coin->MAXPEERS : coin->peers.numranked;
if ( (rand() % 100) < 50 )
height = addr->rank * _IGUANA_MAXPENDING;
else if ( (rand() % 100) < 50 )
height = addr->addrind + (addr->rank * (coin->longestchain - coin->blocks.hwmchain.height) / (coin->peers.numranked+1));
else if ( (rand() % 100) < 50 )
{
height = (addr->lastheight + 1);
if ( height >= coin->longestchain-coin->chain->bundlesize )
height = addr->rank*incr*_IGUANA_MAXPENDING;
}
else
{
height = coin->longestchain - (rand() % incr) * 1000;
if ( height < 0 )
height = coin->blocks.hwmchain.height;
}
for (; height<coin->bundlescount*coin->chain->bundlesize; height+=incr)
{
if ( height > coin->longestchain )
height = addr->rank*incr*_IGUANA_MAXPENDING;
if ( height > addr->lastheight )
addr->lastheight = height;
if ( (bp= coin->bundles[height/coin->chain->bundlesize]) != 0 && bp->emitfinish == 0 )
{
bundlei = (height % coin->chain->bundlesize);
if ( bundlei < bp->n && bits256_nonz(bp->hashes[bundlei]) > 0 && (block= bp->blocks[bundlei]) != 0 && block->numrequests <= bp->minrequests && block->fpipbits == 0 && (bp->issued[bundlei] == 0 || now > bp->issued[bundlei]+13) )
{
block->numrequests++;
bp->issued[bundlei] = (uint32_t)time(NULL);;
//if ( 0 && (rand() % 100) == 0 )
printf("%s Send auto blockreq.%d [%d] minreq.%d\n",addr->ipaddr,bp->bundleheight+bundlei,block->numrequests,bp->minrequests);
iguana_sendblockreqPT(coin,addr,bp,bundlei,bp->hashes[bundlei],0);
return(1);
}
}
//if ( (rand() % 100) < 50 )
// break;
}
}
else
{
//printf("%s lastpoll.%u %u\n",addr->ipaddr,addr->lastpoll,now);
addr->lastpoll = now;
for (i=n=0; i<coin->bundlescount; i++)
if ( coin->bundles[i] != 0 && coin->bundles[i]->emitfinish == 0 )
n++;
if ( n >= coin->bundlescount-(coin->bundlescount>>3) || (addr->ipbits % 10) < 5 )
refbundlei = (addr->ipbits % coin->bundlescount);
else
{
if ( n*2 < coin->bundlescount )
{
for (i=refbundlei=0; i<IGUANA_MAXPEERS; i++)
{
if ( addr->usock == coin->peers.active[i].usock )
break;
if ( coin->peers.active[i].usock >= 0 )
refbundlei++;
}
//printf("half done\n");
} else refbundlei = ((addr->addrind*100) % coin->bundlescount);
}
for (i=0; i<coin->bundlescount; i++)
{
if ( (diff= (i - refbundlei)) < 0 )
diff = -diff;
if ( (bp= coin->bundles[i]) != 0 && bp->emitfinish == 0 )
{
metric = (1 + diff * ((addr->addrind&1) == 0 ? 1 : 1) * (1. + bp->metric));// / (i*((addr->addrind&1) != 0 ? 1 : i) + 1);
//printf("%f ",bp->metric);
if ( bestmetric < 0. || metric < bestmetric )
bestmetric = metric, bestbp = bp;
}
}
if ( bestbp != 0 && bp->emitfinish == 0 )
{
for (k=0; k<coin->bundlescount; k++)
{
i = (bestbp->hdrsi + k) % coin->bundlescount;
if ( (bp= coin->bundles[i]) == 0 || bp->emitfinish != 0 )
continue;
//printf("%.15f ref.%d addrind.%d bestbp.%d\n",bestmetric,refbundlei,addr->addrind,bp->hdrsi);
m = coin->chain->bundlesize;
if ( bp->n < m )
m = bp->n;
j = (addr->addrind*3 + 0) % m;
val = (bp->threshold / 1000.);
for (r=0; r<m; r++,j++)
{
if ( j >= m )
j = 0;
if ( (block= bp->blocks[j]) != 0 && block->fpipbits == 0 && block->queued == 0 && block->numrequests <= bp->minrequests )
{
block->numrequests++;
//block->issued = (uint32_t)time(NULL);;
//printf("%s Send auto blockreq.%d\n",addr->ipaddr,bp->bundleheight+j);
iguana_sendblockreqPT(coin,addr,bp,j,hash2,0);
return(1);
}
}
}
}
}
}
void iguana_bundlestats(struct iguana_info *coin,char *str)
{
int32_t i,n,dispflag,numrecv,done,numhashes,numcached,numsaved,numemit; int64_t estsize = 0;
struct iguana_bundle *bp;
dispflag = (rand() % 1000) == 0;
numrecv = numhashes = numcached = numsaved = numemit = done = 0;
memset(coin->rankedbps,0,sizeof(coin->rankedbps));
for (i=n=0; i<coin->bundlescount; i++)
{
coin->rankedbps[n][1] = i;
if ( (bp= coin->bundles[i]) != 0 )
{
estsize += iguana_bundlecalcs(coin,bp);
numhashes += bp->numhashes;
numcached += bp->numcached;
numrecv += bp->numrecv;
numsaved += bp->numsaved;
if ( bp->emitfinish != 0 )
{
done++;
if ( bp->emitfinish > 1 )
numemit++;
iguana_bundlepurge(coin,bp);
}
else if ( bp->metric > 0. )
coin->rankedbps[n++][0] = bp->metric;
}
}
if ( n > 0 )
{
struct iguana_peer *addr; uint32_t now; struct iguana_block *block; int32_t m,flag,origissue,j,issue,pend = 0;
flag = m = 0;
sortds(&coin->rankedbps[0][0],n,sizeof(coin->rankedbps[0]));
for (i=0; i<coin->peers.numranked; i++)
{
if ( (addr= coin->peers.ranked[i]) != 0 && addr->msgcounts.verack > 0 )
pend += addr->pendblocks;
}
if ( pend > 0 )
{
origissue = (_IGUANA_MAXPENDING*coin->peers.numranked - pend);
issue = origissue;
now = (uint32_t)time(NULL);
for (i=0; i<n; i++)
{
if ( issue <= 0 )
break;
if ( (bp= coin->bundles[(int32_t)coin->rankedbps[i][1]]) != 0 && bp->emitfinish == 0 && bp->numhashes == bp->n )
{
for (j=0; j<bp->n; j++)
{
if ( bits256_nonz(bp->hashes[j]) > 0 && (block= bp->blocks[j]) != 0 )
{
//printf("j.%d bp.%d %d %x lag.%d\n",j,bp->minrequests,block->numrequests,block->fpipbits,now - bp->issued[j]);
if ( block->numrequests <= bp->minrequests+10 && block->fpipbits == 0 && (bp->issued[j] == 0 || now > bp->issued[j]+60) )
{
printf("%d:%d.%d ",bp->hdrsi,j,block->numrequests);
flag++;
bp->issued[j] = now;
iguana_blockQ(coin,bp,j,bp->hashes[j],0);
if ( --issue < 0 )
break;
}
}
}
}
}
/*for (i=0; i<n&&i<3; i++)
printf("(%.5f %.0f).%d ",coin->rankedbps[i][0],coin->rankedbps[i][1],coin->bundles[(int32_t)coin->rankedbps[i][1]]->numrecv);*/
if ( flag != 0 )
printf("rem.%d issue.%d pend.%d | numranked.%d\n",n,origissue,pend,coin->peers.numranked);
}
}
coin->numremain = n;
coin->blocksrecv = numrecv;
char str2[65]; uint64_t tmp; int32_t diff,p = 0; struct tai difft,t = tai_now();
for (i=0; i<IGUANA_MAXPEERS; i++)
if ( coin->peers.active[i].usock >= 0 )
p++;
diff = (int32_t)time(NULL) - coin->startutc;
difft.x = (t.x - coin->starttime.x), difft.millis = (t.millis - coin->starttime.millis);
tmp = (difft.millis * 1000000);
tmp %= 1000000000;
difft.millis = ((double)tmp / 1000000.);
sprintf(str,"N[%d] Q.%d h.%d r.%d c.%d:%d:%d s.%d d.%d E.%d:%d M.%d L.%d est.%d %s %d:%02d:%02d %03.3f peers.%d/%d Q.(%d %d)",coin->bundlescount,coin->numbundlesQ,numhashes,coin->blocksrecv,coin->numcached,numcached,coin->cachefreed,numsaved,done,numemit,coin->numreqsent,coin->blocks.hwmchain.height,coin->longestchain,coin->MAXBUNDLES,mbstr(str2,estsize),(int32_t)difft.x/3600,(int32_t)(difft.x/60)%60,(int32_t)difft.x%60,difft.millis,p,coin->MAXPEERS,queue_size(&coin->priorityQ),queue_size(&coin->blocksQ));
//sprintf(str+strlen(str),"%s.%-2d %s time %.2f files.%d Q.%d %d\n",coin->symbol,flag,str,(double)(time(NULL)-coin->starttime)/60.,coin->peers.numfiles,queue_size(&coin->priorityQ),queue_size(&coin->blocksQ));
//if ( (rand() % 100) == 0 )
static uint32_t lastdisp;
if ( time(NULL) > lastdisp+10 )
{
printf("%s\n",str);
lastdisp = (uint32_t)time(NULL);
}
strcpy(coin->statusstr,str);
coin->estsize = estsize;
}
char *iguana_bundledisp(struct iguana_info *coin,struct iguana_bundle *prevbp,struct iguana_bundle *bp,struct iguana_bundle *nextbp,int32_t m)
{
static char line[1024];
line[0] = 0;
if ( bp == 0 )
return(line);
if ( prevbp != 0 )
{
if ( memcmp(prevbp->hashes[0].bytes,bp->prevbundlehash2.bytes,sizeof(bits256)) == 0 )
{
if ( memcmp(prevbp->nextbundlehash2.bytes,bp->hashes[0].bytes,sizeof(bits256)) == 0 )
sprintf(line+strlen(line),"<->");
else sprintf(line+strlen(line),"<-");
}
else if ( memcmp(prevbp->nextbundlehash2.bytes,bp->hashes[0].bytes,sizeof(bits256)) == 0 )
sprintf(line+strlen(line),"->");
}
sprintf(line+strlen(line),"(%d:%d).%d ",bp->hdrsi,m,bp->numhashes);
if ( nextbp != 0 )
{
if ( memcmp(nextbp->hashes[0].bytes,bp->nextbundlehash2.bytes,sizeof(bits256)) == 0 )
{
if ( memcmp(nextbp->prevbundlehash2.bytes,bp->hashes[0].bytes,sizeof(bits256)) == 0 )
sprintf(line+strlen(line),"<->");
else sprintf(line+strlen(line),"->");
}
else if ( memcmp(nextbp->prevbundlehash2.bytes,bp->hashes[0].bytes,sizeof(bits256)) == 0 )
sprintf(line+strlen(line),"<-");
}
return(line);
}
if ( strcmp(method,"status") == 0 || strcmp(method,"getinfo") == 0 )
return(iguana_getinfo(myinfo,coin));
/* else if ( strcmp(method,"getbestblockhash") == 0 )
return(iguana_getbestblockhash(myinfo,coin));
else if ( strcmp(method,"getblockcount") == 0 )
return(iguana_getblockcount(myinfo,coin));
else if ( strcmp(method,"validatepubkey") == 0 )
return(iguana_validatepubkey(myinfo,coin,jstr(json,"pubkey")));
else if ( strcmp(method,"listtransactions") == 0 )
return(iguana_listtransactions(myinfo,coin,jstr(json,"account"),juint(json,"count"),juint(json,"from")));
else if ( strcmp(method,"getreceivedbyaddress") == 0 )
return(iguana_getreceivedbyaddress(myinfo,coin,jstr(json,"address"),juint(json,"minconf")));
else if ( strcmp(method,"listreceivedbyaddress") == 0 )
return(iguana_listreceivedbyaddress(myinfo,coin,juint(json,"minconf"),juint(json,"includeempty")));
else if ( strcmp(method,"listsinceblock") == 0 )
return(iguana_listsinceblock(myinfo,coin,jbits256(json,"blockhash"),juint(json,"target")));
else if ( strcmp(method,"getreceivedbyaccount") == 0 )
return(iguana_getreceivedbyaccount(myinfo,coin,jstr(json,"account"),juint(json,"minconf")));
else if ( strcmp(method,"listreceivedbyaccount") == 0 )
return(iguana_listreceivedbyaccount(myinfo,coin,jstr(json,"account"),juint(json,"includeempty")));
else if ( strcmp(method,"getnewaddress") == 0 )
return(iguana_getnewaddress(myinfo,coin,jstr(json,"account")));
else if ( strcmp(method,"makekeypair") == 0 )
return(iguana_makekeypair(myinfo,coin));
else if ( strcmp(method,"getaccountaddress") == 0 )
return(iguana_getaccountaddress(myinfo,coin,jstr(json,"account")));
else if ( strcmp(method,"setaccount") == 0 )
return(iguana_setaccount(myinfo,coin,jstr(json,"address"),jstr(json,"account")));
else if ( strcmp(method,"getaccount") == 0 )
return(iguana_getaccount(myinfo,coin,jstr(json,"account")));
else if ( strcmp(method,"getaddressesbyaccount") == 0 )
return(iguana_getaddressesbyaccount(myinfo,coin,jstr(json,"account")));
else if ( strcmp(method,"listaddressgroupings") == 0 )
return(iguana_listaddressgroupings(myinfo,coin));
else if ( strcmp(method,"getbalance") == 0 )
return(iguana_getbalance(myinfo,coin,jstr(json,"account"),juint(json,"minconf")));
else if ( strcmp(method,"listaccounts") == 0 )
return(iguana_listaccounts(myinfo,coin,juint(json,"minconf")));
else if ( strcmp(method,"dumpprivkey") == 0 )
return(iguana_dumpprivkey(myinfo,coin,jstr(json,"address")));
else if ( strcmp(method,"importprivkey") == 0 )
return(iguana_importprivkey(myinfo,coin,jstr(json,"wip")));
else if ( strcmp(method,"dumpwallet") == 0 )
return(iguana_dumpwallet(myinfo,coin));
else if ( strcmp(method,"importwallet") == 0 )
return(iguana_importwallet(myinfo,coin,jstr(json,"wallet")));
else if ( strcmp(method,"walletpassphrase") == 0 )
return(iguana_walletpassphrase(myinfo,coin,jstr(json,"passphrase"),juint(json,"timeout")));
else if ( strcmp(method,"walletpassphrasechange") == 0 )
return(iguana_walletpassphrasechange(myinfo,coin,jstr(json,"oldpassphrase"),jstr(json,"newpassphrase")));
else if ( strcmp(method,"walletlock") == 0 )
return(iguana_walletlock(myinfo,coin));
else if ( strcmp(method,"encryptwallet") == 0 )
return(iguana_encryptwallet(myinfo,coin,jstr(json,"passphrase")));
else if ( strcmp(method,"checkwallet") == 0 )
return(iguana_checkwallet(myinfo,coin));
else if ( strcmp(method,"repairwallet") == 0 )
return(iguana_repairwallet(myinfo,coin));
else if ( strcmp(method,"backupwallet") == 0 )
return(iguana_backupwallet(myinfo,coin,jstr(json,"filename")));
else if ( strcmp(method,"signmessage") == 0 )
return(iguana_signmessage(myinfo,coin,jstr(json,"address"),jstr(json,"message")));
else if ( strcmp(method,"verifymessage") == 0 )
return(iguana_verifymessage(myinfo,coin,jstr(json,"address"),jstr(json,"sig"),jstr(json,"message")));
else if ( strcmp(method,"listunspent") == 0 )
return(iguana_listunspent(myinfo,coin,juint(json,"minconf"),juint(json,"maxconf")));
else if ( strcmp(method,"lockunspent") == 0 )
return(iguana_lockunspent(myinfo,coin,juint(json,"flag"),jobj(json,"array")));
else if ( strcmp(method,"listlockunspent") == 0 )
return(iguana_listlockunspent(myinfo,coin));
else if ( strcmp(method,"gettxout") == 0 )
return(iguana_gettxout(myinfo,coin,jbits256(json,"txid"),juint(json,"vout"),juint(json,"mempool")));
else if ( strcmp(method,"gettxoutsetinfo") == 0 )
return(iguana_gettxoutsetinfo(myinfo,coin));
else if ( strcmp(method,"sendtoaddress") == 0 )
return(iguana_sendtoaddress(myinfo,coin,jstr(json,"address"),jdouble(json,"amount"),jstr(json,"comment"),jstr(json,"comment2")));
else if ( strcmp(method,"move") == 0 )
return(iguana_move(myinfo,coin,jstr(json,"fromaccount"),jstr(json,"toaccount"),jdouble(json,"amount"),juint(json,"minconf"),jstr(json,"comment")));
else if ( strcmp(method,"sendfrom") == 0 )
return(iguana_sendfrom(myinfo,coin,jstr(json,"fromaccount"),jstr(json,"toaddress"),jdouble(json,"amount"),juint(json,"minconf"),jstr(json,"comment"),jstr(json,"comment2")));
else if ( strcmp(method,"sendmany") == 0 )
return(iguana_sendmany(myinfo,coin,jstr(json,"fromaccount"),jobj(json,"payments"),juint(json,"minconf"),jstr(json,"comment")));
else if ( strcmp(method,"settxfee") == 0 )
return(iguana_settxfee(myinfo,coin,jdouble(json,"amount")));
else if ( strcmp(method,"getrawtransaction") == 0 )
return(iguana_getrawtransaction(myinfo,coin,jbits256(json,"txid"),juint(json,"verbose")));
else if ( strcmp(method,"createrawtransaction") == 0 )
return(iguana_createrawtransaction(myinfo,coin,jobj(json,"vins"),jobj(json,"vouts")));
else if ( strcmp(method,"decoderawtransaction") == 0 )
return(iguana_decoderawtransaction(myinfo,coin,jstr(json,"rawtx")));
else if ( strcmp(method,"decodescript") == 0 )
return(iguana_decodescript(myinfo,coin,jstr(json,"script")));
else if ( strcmp(method,"signrawtransaction") == 0 )
return(iguana_signrawtransaction(myinfo,coin,jstr(json,"rawtx"),jobj(json,"vins"),jobj(json,"privkeys")));
else if ( strcmp(method,"sendrawtransaction") == 0 )
return(iguana_sendrawtransaction(myinfo,coin,jstr(json,"rawtx")));
else if ( strcmp(method,"getrawchangeaddress") == 0 )
return(iguana_getrawchangeaddress(myinfo,coin,jstr(json,"account")));
*/
char *iguana_jsoncheck(char *retstr,int32_t freeflag)
{
cJSON *retjson; char *errstr;
if ( retstr != 0 )
{
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (errstr= jstr(retjson,"error")) == 0 )
{
free_json(retjson);
return(retstr);
}
free_json(retjson);
}
if ( freeflag != 0 )
free(retstr);
}
return(0);
}
char *ramchain_parser(struct supernet_info *myinfo,char *method,cJSON *json,char *remoteaddr)
{
char *symbol,*str,*retstr; int32_t height; cJSON *argjson,*obj; struct iguana_info *coin = 0;
/*{"agent":"ramchain","method":"block","coin":"BTCD","hash":"<sha256hash>"}
{"agent":"ramchain","method":"block","coin":"BTCD","height":345600}
{"agent":"ramchain","method":"tx","coin":"BTCD","txid":"<sha txid>"}
{"agent":"ramchain","method":"rawtx","coin":"BTCD","txid":"<sha txid>"}
{"agent":"ramchain","method":"balance","coin":"BTCD","address":"<coinaddress>"}
{"agent":"ramchain","method":"balance","coin":"BTCD","addrs":["<coinaddress>",...]}
{"agent":"ramchain","method":"totalreceived","coin":"BTCD","address":"<coinaddress>"}
{"agent":"ramchain","method":"totalsent","coin":"BTCD","address":"<coinaddress>"}
{"agent":"ramchain","method":"unconfirmed","coin":"BTCD","address":"<coinaddress>"}
{"agent":"ramchain","method":"utxo","coin":"BTCD","address":"<coinaddress>"}
{"agent":"ramchain","method":"utxo","coin":"BTCD","addrs":["<coinaddress0>", "<coinadress1>",...]}
{"agent":"ramchain","method":"txs","coin":"BTCD","block":"<blockhash>"}
{"agent":"ramchain","method":"txs","coin":"BTCD","height":12345}
{"agent":"ramchain","method":"txs","coin":"BTCD","address":"<coinaddress>"}
{"agent":"ramchain","method":"status","coin":"BTCD"}*/
if ( (symbol= jstr(json,"coin")) != 0 && symbol[0] != 0 )
{
if ( coin == 0 )
coin = iguana_coinfind(symbol);
else if ( strcmp(symbol,coin->symbol) != 0 )
return(clonestr("{\"error\":\"mismatched coin symbol\"}"));
}
if ( strcmp(method,"explore") == 0 )
{
obj = jobj(json,"search");
if ( coin != 0 && obj != 0 )
{
argjson = cJSON_CreateObject();
jaddstr(argjson,"agent","ramchain");
jaddstr(argjson,"method","block");
jaddnum(argjson,"txids",1);
if ( is_cJSON_Number(obj) != 0 )
{
height = juint(obj,0);
jaddnum(argjson,"height",height);
}
else if ( (str= jstr(obj,0)) != 0 )
jaddstr(argjson,"hash",str);
else return(clonestr("{\"error\":\"need number or string to search\"}"));
if ( (retstr= iguana_jsoncheck(ramchain_coinparser(myinfo,coin,"block",argjson),1)) != 0 )
{
free_json(argjson);
return(retstr);
}
free_json(argjson);
argjson = cJSON_CreateObject();
jaddstr(argjson,"agent","ramchain");
jaddstr(argjson,"method","tx");
jaddstr(argjson,"txid",str);
if ( (retstr= iguana_jsoncheck(ramchain_coinparser(myinfo,coin,"tx",argjson),1)) != 0 )
{
free_json(argjson);
return(retstr);
}
free_json(argjson);
return(clonestr("{\"result\":\"explore search cant find height, blockhash, txid\"}"));
}
return(clonestr("{\"result\":\"explore no coin or search\"}"));
}
return(ramchain_coinparser(myinfo,coin,method,json));
}
/*int32_t pp_bind(char *hostname,uint16_t port)
{
int32_t opt; struct sockaddr_in addr; socklen_t addrlen = sizeof(addr);
struct hostent* hostent = gethostbyname(hostname);
if (hostent == NULL) {
PNACL_message("gethostbyname() returned error: %d", errno);
return -1;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
memcpy(&addr.sin_addr.s_addr, hostent->h_addr_list[0], hostent->h_length);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
printf("socket() failed: %s", strerror(errno));
return -1;
}
opt = 1;
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&opt,sizeof(opt));
#ifdef __APPLE__
setsockopt(sock,SOL_SOCKET,SO_NOSIGPIPE,&opt,sizeof(opt));
#endif
//timeout.tv_sec = 0;
//timeout.tv_usec = 1000;
//setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout));
int result = bind(sock, (struct sockaddr*)&addr, addrlen);
if (result != 0) {
printf("bind() failed: %s", strerror(errno));
closesocket(sock);
return -1;
}
return(sock);
}*/
/*if ( strcmp(agent,"ramchain") == 0 )
return(ramchain_parser(myinfo,method,json,remoteaddr));
else if ( strcmp(agent,"InstantDEX") == 0 )
return(InstantDEX_parser(myinfo,method,json,remoteaddr));
else if ( strcmp(agent,"pangea") == 0 )
return(pangea_parser(myinfo,method,json,remoteaddr));
else if ( strcmp(agent,"jumblr") == 0 )
return(jumblr_parser(myinfo,method,json,remoteaddr));
else if ( strcmp(agent,"hash") == 0 )
return(hash_parser(myinfo,method,json,remoteaddr));*/
char *iguana_coinjson(struct iguana_info *coin,char *method,cJSON *json)
{
int32_t i,max,retval,num=0; char buf[1024]; struct iguana_peer *addr; char *ipaddr; cJSON *retjson = 0;
//printf("iguana_coinjson(%s)\n",jprint(json,0));
if ( strcmp(method,"peers") == 0 )
return(jprint(iguana_peersjson(coin,0),1));
else if ( strcmp(method,"getconnectioncount") == 0 )
{
for (i=0; i<sizeof(coin->peers.active)/sizeof(*coin->peers.active); i++)
if ( coin->peers.active[i].usock >= 0 )
num++;
sprintf(buf,"{\"result\":\"%d\"}",num);
return(clonestr(buf));
}
else if ( strcmp(method,"addnode") == 0 )
{
if ( (ipaddr= jstr(json,"ipaddr")) != 0 )
{
iguana_possible_peer(coin,ipaddr);
return(clonestr("{\"result\":\"addnode submitted\"}"));
} else return(clonestr("{\"error\":\"addnode needs ipaddr\"}"));
}
else if ( strcmp(method,"removenode") == 0 )
{
if ( (ipaddr= jstr(json,"ipaddr")) != 0 )
{
for (i=0; i<IGUANA_MAXPEERS; i++)
{
if ( strcmp(coin->peers.active[i].ipaddr,ipaddr) == 0 )
{
coin->peers.active[i].rank = 0;
coin->peers.active[i].dead = (uint32_t)time(NULL);
return(clonestr("{\"result\":\"node marked as dead\"}"));
}
}
return(clonestr("{\"result\":\"node wasnt active\"}"));
} else return(clonestr("{\"error\":\"removenode needs ipaddr\"}"));
}
else if ( strcmp(method,"oneshot") == 0 )
{
if ( (ipaddr= jstr(json,"ipaddr")) != 0 )
{
iguana_possible_peer(coin,ipaddr);
return(clonestr("{\"result\":\"addnode submitted\"}"));
} else return(clonestr("{\"error\":\"addnode needs ipaddr\"}"));
}
else if ( strcmp(method,"nodestatus") == 0 )
{
if ( (ipaddr= jstr(json,"ipaddr")) != 0 )
{
for (i=0; i<coin->MAXPEERS; i++)
{
addr = &coin->peers.active[i];
if ( strcmp(addr->ipaddr,ipaddr) == 0 )
return(jprint(iguana_peerjson(coin,addr),1));
}
return(clonestr("{\"result\":\"nodestatus couldnt find ipaddr\"}"));
} else return(clonestr("{\"error\":\"nodestatus needs ipaddr\"}"));
}
else if ( strcmp(method,"maxpeers") == 0 )
{
retjson = cJSON_CreateObject();
if ( (max= juint(json,"max")) <= 0 )
max = 1;
else if ( max > IGUANA_MAXPEERS )
max = IGUANA_MAXPEERS;
if ( max > coin->MAXPEERS )
{
for (i=max; i<coin->MAXPEERS; i++)
if ( (addr= coin->peers.ranked[i]) != 0 )
addr->dead = 1;
}
coin->MAXPEERS = max;
jaddnum(retjson,"maxpeers",coin->MAXPEERS);
jaddstr(retjson,"coin",coin->symbol);
return(jprint(retjson,1));
}
else if ( strcmp(method,"startcoin") == 0 )
{
coin->active = 1;
return(clonestr("{\"result\":\"coin started\"}"));
}
else if ( strcmp(method,"pausecoin") == 0 )
{
coin->active = 0;
return(clonestr("{\"result\":\"coin paused\"}"));
}
else if ( strcmp(method,"addcoin") == 0 )
{
if ( (retval= iguana_launchcoin(coin->symbol,json)) > 0 )
return(clonestr("{\"result\":\"coin added\"}"));
else if ( retval == 0 )
return(clonestr("{\"result\":\"coin already there\"}"));
else return(clonestr("{\"error\":\"error adding coin\"}"));
}
return(clonestr("{\"error\":\"unhandled request\"}"));
}
char *iguana_parser(struct supernet_info *myinfo,char *method,cJSON *json,char *remoteaddr)
{
char *coinstr,SYM[16]; int32_t j,k,l,r,rr; struct iguana_peer *addr;
cJSON *retjson = 0,*array; int32_t i,n; struct iguana_info *coin; char *symbol;
printf("remoteaddr.(%s)\n",remoteaddr!=0?remoteaddr:"local");
if ( remoteaddr == 0 || remoteaddr[0] == 0 || strcmp(remoteaddr,"127.0.0.1") == 0 ) // local (private) api
{
if ( strcmp(method,"list") == 0 )
{
retjson = cJSON_CreateObject();
array = cJSON_CreateArray();
for (i=0; i<sizeof(Coins)/sizeof(*Coins); i++)
{
if ( Coins[i] != 0 && Coins[i]->symbol[0] != 0 )
jaddistr(array,Coins[i]->symbol);
}
jadd(retjson,"coins",array);
return(jprint(retjson,1));
}
else if ( strcmp(method,"allpeers") == 0 )
{
retjson = cJSON_CreateObject();
array = cJSON_CreateArray();
for (i=0; i<sizeof(Coins)/sizeof(*Coins); i++)
{
if ( Coins[i] != 0 && Coins[i]->symbol[0] != 0 )
jaddi(array,iguana_peersjson(Coins[i],0));
}
jadd(retjson,"allpeers",array);
return(jprint(retjson,1));
}
else
{
if ( (symbol= jstr(json,"coin")) != 0 && strlen(symbol) < sizeof(SYM)-1 )
{
strcpy(SYM,symbol);
touppercase(SYM);
if ( (coin= iguana_coinfind(SYM)) == 0 )
{
if ( strcmp(method,"addcoin") == 0 )
coin = iguana_coinadd(SYM);
}
if ( coin != 0 )
return(iguana_coinjson(coin,method,json));
else return(clonestr("{\"error\":\"cant get coin info\"}"));
}
}
}
array = 0;
if ( strcmp(method,"getpeers") == 0 )
{
if ( (coinstr= jstr(json,"coin")) != 0 )
{
if ( (array= iguana_peersjson(iguana_coinfind(coinstr),1)) == 0 )
return(clonestr("{\"error\":\"coin not found\"}"));
}
else
{
n = 0;
array = cJSON_CreateArray();
r = rand();
for (i=0; i<IGUANA_MAXCOINS; i++)
{
j = (r + i) % IGUANA_MAXCOINS;
if ( (coin= Coins[j]) != 0 )
{
rr = rand();
for (k=0; k<IGUANA_MAXPEERS; k++)
{
l = (rr + k) % IGUANA_MAXPEERS;
addr = &coin->peers.active[l];
if ( addr->usock >= 0 && addr->supernet != 0 )
{
jaddistr(array,addr->ipaddr);
if ( ++n >= 64 )
break;
}
}
}
}
}
if ( array != 0 )
{
retjson = cJSON_CreateObject();
jaddstr(retjson,"agent","SuperNET");
jaddstr(retjson,"method","mypeers");
jaddstr(retjson,"result","peers found");
jadd(retjson,"peers",array);
return(jprint(retjson,1));
} else return(clonestr("{\"error\":\"no peers found\"}"));
}
else if ( strcmp(method,"mypeers") == 0 )
{
printf("mypeers from %s\n",remoteaddr!=0?remoteaddr:"local");
}
return(clonestr("{\"result\":\"stub processed generic json\"}"));
}
char *InstantDEX_parser(struct supernet_info *myinfo,char *method,cJSON *json,char *remoteaddr)
{
return(clonestr("{\"error\":\"InstantDEX API is not yet\"}"));
}
char *jumblr_parser(struct supernet_info *myinfo,char *method,cJSON *json,char *remoteaddr)
{
return(clonestr("{\"error\":\"jumblr API is not yet\"}"));
}
char *pangea_parser(struct supernet_info *myinfo,char *method,cJSON *json,char *remoteaddr)
{
return(clonestr("{\"error\":\"jumblr API is not yet\"}"));
}
/*
char *hash_parser(struct supernet_info *myinfo,char *hashname,cJSON *json,char *remoteaddr)
{
int32_t i,len,iter,n; uint8_t databuf[512];
char hexstr[1025],*password,*name,*msg;
typedef void (*hashfunc)(char *hexstr,uint8_t *buf,uint8_t *msg,int32_t len);
typedef char *(*hmacfunc)(char *dest,char *key,int32_t key_size,char *message);
struct hashfunc_entry { char *name; hashfunc hashfunc; };
struct hmacfunc_entry { char *name; hmacfunc hmacfunc; };
struct hashfunc_entry hashes[] = { {"NXT",calc_NXTaddr}, {"curve25519",calc_curve25519_str }, {"base64_encode",calc_base64_encodestr}, {"base64_decode",calc_base64_decodestr}, {"crc32",calc_crc32str}, {"rmd160_sha256",rmd160ofsha256}, {"sha256_sha256",sha256_sha256}, {"sha256",vcalc_sha256}, {"sha512",calc_sha512}, {"sha384",calc_sha384}, {"sha224",calc_sha224}, {"rmd160",calc_rmd160}, {"rmd256",calc_rmd256}, {"rmd320",calc_rmd320}, {"rmd128",calc_rmd128}, {"sha1",calc_sha1}, {"md5",calc_md5str}, {"md2",calc_md2str}, {"md4",calc_md4str}, {"tiger",calc_tiger}, {"whirlpool",calc_whirlpool} };
struct hmacfunc_entry hmacs[] = { {"hmac_sha256",hmac_sha256_str}, {"hmac_sha512",hmac_sha512_str}, {"hmac_sha384",hmac_sha384_str}, {"hmac_sha224",hmac_sha224_str}, {"hmac_rmd160",hmac_rmd160_str}, {"hmac_rmd256",hmac_rmd256_str}, {"hmac_rmd320",hmac_rmd320_str}, {"hmac_rmd128",hmac_rmd128_str}, {"hmac_sha1",hmac_sha1_str}, {"hmac_md52",hmac_md2_str},{"hmac_md4",hmac_md4_str},{"hmac_md5",hmac_md5_str}, {"hmac_tiger",hmac_tiger_str}, {"hmac_whirlpool",hmac_whirlpool_str} };
if ( (msg= jstr(json,"message")) == 0 )
return(clonestr("{\"error\":\"no message to hash\"}"));
if ( (password= jstr(json,"password")) == 0 || password[0] == 0 )
password = " ";
n = (int32_t)sizeof(hashes)/sizeof(*hashes);
printf("msg.(%s) password.(%s)\n",msg,password!=0?password:"");
for (iter=0; iter<2; iter++)
{
for (i=0; i<n; i++)
{
name = (iter == 0) ? hashes[i].name : hmacs[i].name;
//printf("iter.%d i.%d (%s) vs (%s) %d\n",iter,i,name,hashname,strcmp(hashname,name) == 0);
if ( strcmp(hashname,name) == 0 )
{
json = cJSON_CreateObject();
len = msg==0?0:(int32_t)strlen(msg);
if ( iter == 0 )
(*hashes[i].hashfunc)(hexstr,databuf,(uint8_t *)msg,len);
else (*hmacs[i].hmacfunc)(hexstr,password,password==0?0:(int32_t)strlen(password),msg);
jaddstr(json,"result","hash calculated");
jaddstr(json,"message",msg);
jaddstr(json,name,hexstr);
return(jprint(json,1));
}
}
n = (int32_t)sizeof(hmacs)/sizeof(*hmacs);
}
return(clonestr("{\"error\":\"cant find hash function\"}"));
}*/
/*cJSON *SuperNET_transportencode(struct supernet_info *myinfo,bits256 destpub,cJSON *json,char *destip)
{
char str[65]; uint64_t r;
if ( j64bits(json,"tag") == 0 )
{
OS_randombytes((uint8_t *)&r,sizeof(r));
jadd64bits(json,"tag",r);
}
jdelete(json,"yourip");
jaddstr(json,"yourip",destip);
jdelete(json,"mypub");
jaddstr(json,"mypub",bits256_str(str,myinfo->myaddr.pubkey));
jdelete(json,"myip");
jaddstr(json,"myip",myinfo->ipaddr);
return(json);
}*/
void ramcoder_test(void *data,int64_t datalen)
{
static double totalin,totalout;
int32_t complen,bufsize = 1024 * 1024; uint8_t *buf;
buf = malloc(bufsize);
complen = ramcoder_compress(buf,bufsize,data,(int32_t)datalen);
totalin += datalen;
totalout += (complen >> 3);
printf("datalen.%d -> numbits.%d %d %.3f\n",(int32_t)datalen,complen,complen>>3,(double)totalin/totalout);
free(buf);
}
/*if ( (msgjson= cJSON_Parse(message)) != 0 )
{
if ( (agent= jstr(msgjson,"agent")) != 0 && strcmp(agent,"SuperNET")) != 0 )
{
safecopy(agentstr,agent,sizeof(agentstr)-1);
jdelete(msgjson,"agent");
jaddstr(msgjson,"agent","SuperNET");
jaddstr(msgjson,"destagent",agentstr);
}
if ( (method= jstr(msgjson,"method")) != 0 && strcmp(agent,"SuperNET")) != 0 )
{
safecopy(methodstr,method,sizeof(methodstr)-1);
jdelete(msgjson,"method");
jaddstr(msgjson,"method","DHTsend");
jaddstr(msgjson,"destmethod",methodstr);
}
msgstr = jprint(msgjson,1);
msglen = (int32_t)strlen(msgstr);
hexstr = calloc(1,msglen*2+1);
flag = 1;
init_hexbytes_noT(hexstr,msgstr,msglen);
}
if ( flag != 0 )
free(hexstr);*/
//char str[65],str2[65],str3[65],str4[65];
//int32_t i; for (i=0; i<len; i++)
// printf("%02x ",serialized[i]);
//printf("ORIG SERIALIZED.%d\n",len);
//printf("mypriv.%s destpub.%s seed.%s seed2.%s -> crc.%08x\n",bits256_str(str,myinfo->privkey),bits256_str(str2,destpub),bits256_str(str3,seed),bits256_str(str4,seed2),crc);
numbits = ramcoder_compress(&compressed[3],maxsize-3,serialized,len,seed2);
compressed[0] = (numbits & 0xff);
compressed[1] = ((numbits>>8) & 0xff);
compressed[2] = ((numbits>>16) & 0xff);
//printf("strlen.%d len.%d -> %s numbits.%d\n",(int32_t)strlen(jprint(json,0)),len,bits256_str(str,seed2),(int32_t)hconv_bitlen(numbits));
if ( 0 )
{
uint8_t space[9999];
int32_t testlen = ramcoder_decompress(space,IGUANA_MAXPACKETSIZE,&compressed[3],numbits,seed2);
printf("len.%d -> testlen.%d cmp.%d\n",len,testlen,memcmp(space,serialized,testlen));
int32_t i; for (i=0; i<3+hconv_bitlen(numbits); i++)
printf("%02x ",compressed[i]);
printf("complen.%d\n",i+3);
}
*complenp = (int32_t)hconv_bitlen(numbits) + 3;
cJSON *SuperNET_bits2json(bits256 senderpub,bits256 sharedseed,uint8_t *serialized,uint8_t *space,int32_t datalen,int32_t iscompressed)
{
char destip[64],method[64],checkstr[5],agent[64],myipaddr[64],str[65],*hexmsg; uint64_t tag;
uint16_t apinum,checkc; uint32_t destipbits,myipbits; bits256 seed2;
int32_t numbits,dlen,iter,flag=0,len = 0; uint32_t crc,checkcrc; cJSON *json = cJSON_CreateObject();
//int32_t i; for (i=0; i<datalen; i++)
// printf("%02x ",serialized[i]);
printf("bits[%d] iscompressed.%d sender.%llx shared.%llx\n",datalen,iscompressed,(long long)senderpub.txid,(long long)sharedseed.txid);
if ( iscompressed != 0 )
{
numbits = serialized[2];
numbits = (numbits << 8) + serialized[1];
numbits = (numbits << 8) + serialized[0];
if ( hconv_bitlen(numbits)+3 == datalen || hconv_bitlen(numbits)+3 == datalen-1 )
{
memset(seed2.bytes,0,sizeof(seed2));
for (iter=0; iter<2; iter++)
{
//char str[65]; printf("compressed len.%d seed2.(%s)\n",numbits,bits256_str(str,seed2));
dlen = ramcoder_decompress(space,IGUANA_MAXPACKETSIZE,&serialized[3],numbits,seed2);
serialized = space;
if ( dlen > sizeof(crc) && dlen < IGUANA_MAXPACKETSIZE )
{
crc = calc_crc32(0,&serialized[sizeof(crc)],dlen - sizeof(crc));
iguana_rwnum(0,serialized,sizeof(checkcrc),&checkcrc);
//int32_t i; for (i=0; i<datalen; i++)
// printf("%02x ",serialized[i]);
printf("bits[%d] numbits.%d after decompress crc.(%08x vs %08x) <<<<<< iter.%d %llx shared.%llx\n",datalen,numbits,crc,checkcrc,iter,(long long)seed2.txid,(long long)sharedseed.txid);
if ( crc == checkcrc )
{
flag = 1;
break;
}
}
seed2 = sharedseed;
}
}
else
{
printf("numbits.%d + 3 -> %d != datalen.%d\n",numbits,(int32_t)hconv_bitlen(numbits)+3,datalen);
return(0);
}
}
if ( flag == 0 )
return(0);
len += iguana_rwnum(0,&serialized[len],sizeof(uint32_t),&crc);
len += iguana_rwnum(0,&serialized[len],sizeof(uint32_t),&destipbits);
len += iguana_rwnum(0,&serialized[len],sizeof(uint32_t),&myipbits);
len += iguana_rwbignum(0,&serialized[len],sizeof(bits256),senderpub.bytes);
len += iguana_rwnum(0,&serialized[len],sizeof(tag),&tag);
len += iguana_rwnum(0,&serialized[len],sizeof(checkc),&checkc);
len += iguana_rwnum(0,&serialized[len],sizeof(apinum),&apinum);
//printf("-> dest.%x myip.%x senderpub.%llx tag.%llu\n",destipbits,myipbits,(long long)senderpub.txid,(long long)tag);
if ( SuperNET_num2API(agent,method,apinum) >= 0 )
{
jaddstr(json,"agent",agent);
jaddstr(json,"method",method);
expand_ipbits(destip,destipbits), jaddstr(json,"yourip",destip);
expand_ipbits(myipaddr,myipbits), jaddstr(json,"myip",myipaddr);
jaddstr(json,"mypub",bits256_str(str,senderpub));
jadd64bits(json,"tag",tag);
init_hexbytes_noT(checkstr,(void *)&checkc,sizeof(checkc));
jaddstr(json,"check",checkstr);
if ( len < datalen )
{
printf("len %d vs %d datalen\n",len,datalen);
hexmsg = malloc(((datalen - len)<<1) + 1);
init_hexbytes_noT(hexmsg,&serialized[len],datalen - len);
printf("hex.(%s)\n",hexmsg);
jaddstr(json,"message",hexmsg);
free(hexmsg);
}
//printf("bits2json.(%s)\n",jprint(json,0));
return(json);
} else printf("cant decode apinum.%d (%d.%d)\n",apinum,apinum>>5,apinum%0x1f);
return(0);
}
#ifdef notyet
int32_t SuperNET_serialize(int32_t reverse,bits256 *senderpubp,uint64_t *senderbitsp,bits256 *sigp,uint32_t *timestampp,uint64_t *destbitsp,uint8_t *origbuf)
{
uint8_t *buf = origbuf; long extra = sizeof(bits256) + sizeof(uint64_t) + sizeof(uint64_t);
buf += SuperNET_copybits(reverse,buf,(void *)destbitsp,sizeof(uint64_t));
buf += SuperNET_copybits(reverse,buf,senderpubp->bytes,sizeof(bits256));
buf += SuperNET_copybits(reverse,buf,(void *)senderbitsp,sizeof(uint64_t));
buf += SuperNET_copybits(reverse,buf,(void *)timestampp,sizeof(uint32_t)), extra += sizeof(uint32_t);
if ( *senderbitsp != 0 )
buf += SuperNET_copybits(reverse,buf,sigp->bytes,sizeof(bits256)), extra += sizeof(bits256);
else memset(sigp,0,sizeof(*sigp));
if ( ((long)buf - (long)origbuf) != extra )
{
printf("SuperNET_serialize: extrasize mismatch %ld vs %ld\n",((long)buf - (long)origbuf),extra);
}
return((int32_t)extra);
}
int32_t SuperNET_decode(uint64_t *senderbitsp,bits256 *sigp,uint32_t *timestampp,uint64_t *destbitsp,uint8_t *str,uint8_t *cipher,int32_t *lenp,uint8_t *myprivkey)
{
bits256 srcpubkey; uint8_t *nonce; int i,hdrlen,err=0,len = *lenp;
hdrlen = SuperNET_serialize(1,&srcpubkey,senderbitsp,sigp,timestampp,destbitsp,cipher);
cipher += hdrlen, len -= hdrlen;
if ( *destbitsp != 0 && *senderbitsp != 0 )
{
nonce = cipher;
cipher += crypto_box_NONCEBYTES, len -= crypto_box_NONCEBYTES;
printf("decode ptr.%p[%d]\n",cipher,len);
err = crypto_box_open((uint8_t *)str,cipher,len,nonce,srcpubkey.bytes,myprivkey);
for (i=0; i<len-crypto_box_ZEROBYTES; i++)
str[i] = str[i+crypto_box_ZEROBYTES];
*lenp = len - crypto_box_ZEROBYTES;
} else memcpy(str,cipher,len);
return(err);
}
uint8_t *SuperNET_encode(int32_t *cipherlenp,void *str,int32_t len,bits256 destpubkey,bits256 myprivkey,bits256 mypubkey,uint64_t senderbits,bits256 sig,uint32_t timestamp)
{
uint8_t *buf,*nonce,*origcipher,*cipher,*ptr; uint64_t destbits; int32_t totalsize,hdrlen;
long extra = crypto_box_NONCEBYTES + crypto_box_ZEROBYTES + sizeof(sig);
destbits = (memcmp(destpubkey.bytes,GENESIS_PUBKEY.bytes,sizeof(destpubkey)) != 0) ? acct777_nxt64bits(destpubkey) : 0;
totalsize = (int32_t)(len + sizeof(mypubkey) + sizeof(senderbits) + sizeof(destbits) + sizeof(timestamp));
*cipherlenp = 0;
if ( (buf= calloc(1,totalsize + extra)) == 0 )
{
printf("SuperNET_encode: outof mem for buf[%ld]\n",totalsize+extra);
return(0);
}
if ( (cipher= calloc(1,totalsize + extra + sizeof(struct iguana_msghdr))) == 0 )
{
printf("SuperNET_encode: outof mem for cipher[%ld]\n",totalsize + extra + sizeof(struct iguana_msghdr));
free(buf);
return(0);
}
origcipher = cipher;
ptr = &cipher[sizeof(struct iguana_msghdr)];
hdrlen = SuperNET_serialize(0,&mypubkey,&senderbits,&sig,&timestamp,&destbits,ptr);
printf("hdrlen.%d sender.%llx dest.%llx\n",hdrlen,(long long)senderbits,(long long)destbits);
if ( senderbits != 0 )
totalsize += sizeof(sig);//, printf("totalsize.%d extra.%ld add %ld\n",totalsize-len,extra,(long)(sizeof(sig) + sizeof(timestamp)));
if ( destbits != 0 && senderbits != 0 )
{
totalsize += crypto_box_NONCEBYTES + crypto_box_ZEROBYTES;//, printf("totalsize.%d extra.%ld add %d\n",totalsize-len,extra,crypto_box_NONCEBYTES + crypto_box_ZEROBYTES);
nonce = &ptr[hdrlen];
OS_randombytes(nonce,crypto_box_NONCEBYTES);
cipher = &nonce[crypto_box_NONCEBYTES];
//printf("len.%d -> %d %d\n",len,len+crypto_box_ZEROBYTES,len + crypto_box_ZEROBYTES + crypto_box_NONCEBYTES);
memset(cipher,0,len+crypto_box_ZEROBYTES);
memset(buf,0,crypto_box_ZEROBYTES);
memcpy(buf+crypto_box_ZEROBYTES,str,len);
printf("cryptobox.%p[%d]\n",cipher,len+crypto_box_ZEROBYTES);
crypto_box(cipher,buf,len+crypto_box_ZEROBYTES,nonce,destpubkey.bytes,myprivkey.bytes);
hdrlen += crypto_box_NONCEBYTES + crypto_box_ZEROBYTES;
}
else memcpy(&cipher[hdrlen],str,len);
if ( totalsize != len+hdrlen )
printf("unexpected totalsize.%d != len.%d + hdrlen.%d %d\n",totalsize,len,hdrlen,len+hdrlen);
*cipherlenp = totalsize;
{
bits256 checksig; uint32_t checkstamp; uint64_t checksender,checkbits; int32_t checklen;
checklen = totalsize;
if ( SuperNET_decode(&checksender,&checksig,&checkstamp,&checkbits,(void *)buf,ptr,&checklen,myprivkey.bytes) == 0 )
{
printf("decoded %u %llx checklen.%d\n",checkstamp,(long long)checkbits,checklen);
} else printf("encrypt/decrypt error\n");
printf("decoded %u %llx checklen.%d\n",checkstamp,(long long)checkbits,checklen);
}
free(buf);
return(origcipher);
}
int32_t SuperNET_decrypt(bits256 *senderpubp,uint64_t *senderbitsp,uint32_t *timestampp,bits256 mypriv,bits256 mypub,uint8_t *dest,int32_t maxlen,uint8_t *src,int32_t len)
{
bits256 seed,sig,msgpriv; uint64_t my64bits,destbits,senderbits,sendertmp,desttmp;
uint8_t *buf; int32_t hdrlen,diff,newlen = -1; HUFF H,*hp = &H; struct acct777_sig checksig;
*senderbitsp = 0;
my64bits = acct777_nxt64bits(mypub);
if ( (buf = calloc(1,maxlen)) == 0 )
{
printf("SuperNET_decrypt cant allocate maxlen.%d\n",maxlen);
return(-1);
}
hdrlen = SuperNET_serialize(1,senderpubp,&senderbits,&sig,timestampp,&destbits,src);
if ( destbits != 0 && my64bits != destbits && destbits != acct777_nxt64bits(GENESIS_PUBKEY) )
{
free(buf);
printf("SuperNET_decrypt received destination packet.%llu when my64bits.%llu len.%d\n",(long long)destbits,(long long)my64bits,len);
return(-1);
}
if ( memcmp(mypub.bytes,senderpubp->bytes,sizeof(mypub)) == 0 )
{
if ( destbits != 0 )
printf("SuperNET: got my own msg?\n");
}
printf("decrypt(%d) destbits.%llu my64.%llu mypriv.%llx mypub.%llx senderpub.%llx shared.%llx\n",len,(long long)destbits,(long long)my64bits,(long long)mypriv.txid,(long long)mypub.txid,(long long)senderpubp->txid,(long long)seed.txid);
if ( SuperNET_decode(&sendertmp,&sig,timestampp,&desttmp,(void *)buf,src,&len,mypriv.bytes) == 0 )
{
if ( (diff= (*timestampp - (uint32_t)time(NULL))) < 0 )
diff = -diff;
if ( 1 && diff > SUPERNET_MAXTIMEDIFF )
printf("diff.%d > %d %u vs %u\n",diff,SUPERNET_MAXTIMEDIFF,*timestampp,(uint32_t)time(NULL));
else
{
if ( 0 )
{
memset(seed.bytes,0,sizeof(seed));
//for (i='0'; i<='9'; i++)
// SETBIT(seed.bytes,i);
//for (i='a'; i<='f'; i++)
// SETBIT(seed.bytes,i);
_init_HUFF(hp,len,buf), hp->endpos = (len << 3);
newlen = ramcoder_decoder(0,1,dest,maxlen,hp,&seed);
}
else memcpy(dest,buf,len), newlen = len;
//printf("T%d decrypted newlen.%d\n",threadid,newlen);
if ( senderbits != 0 && senderpubp->txid != 0 )
{
*senderbitsp = senderbits;
if ( destbits == 0 )
msgpriv = GENESIS_PRIVKEY;
else msgpriv = mypriv;
acct777_sign(&checksig,msgpriv,*senderpubp,*timestampp,dest,newlen);
if ( memcmp(checksig.sigbits.bytes,&sig,sizeof(checksig.sigbits)) != 0 )
{
printf("sender.%llu sig %llx compare error vs %llx using sig->pub from %llu, broadcast.%d len.%d -> newlen.%d\n",(long long)senderbits,(long long)sig.txid,(long long)checksig.sigbits.txid,(long long)senderbits,destbits == 0,len,newlen);
//free(buf);
//return(0);
} //else printf("SIG VERIFIED newlen.%d (%llu -> %llu)\n",newlen,(long long)senderbits,(long long)destbits);
}
}
} else printf("%llu: SuperNET_decrypt skip: decode_cipher error len.%d -> newlen.%d\n",(long long)acct777_nxt64bits(mypub),len,newlen);
free(buf);
return(newlen);
}
int32_t SuperNET_sendmsg(struct supernet_info *myinfo,struct iguana_info *coin,struct iguana_peer *addr,bits256 destpub,bits256 mypriv,bits256 mypub,uint8_t *msg,int32_t len,uint8_t *data,int32_t delaymillis)
{
int32_t cipherlen,datalen,qlen=-1; bits256 seed; uint8_t *cipher; uint64_t destbits; struct acct777_sig sig; HUFF H,*hp = &H;
if ( destpub.txid != 0 )
destbits = acct777_nxt64bits(destpub);
else
{
destbits = 0;
destpub = GENESIS_PUBKEY;
}
printf("SuperNET_sendmsg dest.%llu destpub.%llx priv.%llx pub.%llx\n",(long long)destbits,(long long)destpub.txid,(long long)mypriv.txid,(long long)mypub.txid);
memset(&sig,0,sizeof(sig));
if ( mypub.txid == 0 || mypriv.txid == 0 )
mypriv = curve25519_keypair(&mypub), sig.timestamp = (uint32_t)time(NULL);
else acct777_sign(&sig,mypriv,destpub,(uint32_t)time(NULL),msg,len);
if ( 0 )
{
memset(seed.bytes,0,sizeof(seed));
//seed = addr->sharedseed;
data = calloc(1,len*2);
_init_HUFF(hp,len*2,data);
/*for (i='0'; i<='9'; i++)
SETBIT(seed.bytes,i);
for (i='a'; i<='f'; i++)
SETBIT(seed.bytes,i);*/
ramcoder_encoder(0,1,msg,len,hp,0,&seed);
datalen = (int32_t)hconv_bitlen(hp->bitoffset);
}
else data = msg, datalen = len;
if ( (cipher= SuperNET_encode(&cipherlen,data,datalen,destpub,mypriv,mypub,sig.signer64bits,sig.sigbits,sig.timestamp)) != 0 )
{
qlen = iguana_queue_send(coin,addr,delaymillis,cipher,"SuperNETb",cipherlen,0,0);
free(cipher);
}
return(qlen);
}
#endif /*memset(senderpub.bytes,0,sizeof(senderpub));
if ( iscompressed != 0 )
{
if ( (len= SuperNET_decrypt(&senderpub,&senderbits,&timestamp,mypriv,mypub,space,IGUANA_MAXPACKETSIZE,serialized,datalen)) > 1 && len < IGUANA_MAXPACKETSIZE )
{
if ( memcmp(senderpub.bytes,addr->pubkey.bytes,sizeof(senderpub)) != 0 )
{
printf("got new pubkey.(%s) for %s\n",bits256_str(str,senderpub),addr->ipaddr);
addr->pubkey = senderpub;
addr->sharedseed = SuperNET_sharedseed(mypriv,senderpub);
}
serialized = space;
datalen = len;
len = 0;
} else printf("decrypt error len.%d origlen.%d\n",len,datalen);
}*/
bits256 testprivkey(int32_t selector)
{
bits256 privkey;
memset(privkey.bytes,0,sizeof(privkey.bytes));
privkey.bytes[15] = selector;
return(privkey);
}
bits256 testpubkey(int32_t selector)
{
return(acct777_pubkey(testprivkey(selector)));
}
/*char *pangea_univ(uint8_t *mypriv,cJSON *json)
{
char *addrtypes[][3] = { {"BTC","0","80"}, {"LTC","48"}, {"BTCD","60","bc"}, {"DOGE","30"}, {"VRC","70"}, {"OPAL","115"}, {"BITS","25"} };
char *wipstr,*coin,*coinaddr,pubkeystr[67],rsaddr[64],destaddr[64],wifbuf[128]; uint8_t priv[32],pub[33],addrtype; int32_t i;
uint64_t nxt64bits; cJSON *retjson,*item;
PNACL_message("inside rosetta\n");
if ( (coin= jstr(json,"coin")) != 0 )
{
if ( (wipstr= jstr(json,"wif")) != 0 || (wipstr= jstr(json,"wip")) != 0 )
{
PNACL_message("got wip.(%s)\n",wipstr);
btc_wip2priv(priv,wipstr);
}
else if ( (coinaddr= jstr(json,"addr")) != 0 )
{
if ( getprivkey(priv,coin,coinaddr) < 0 )
return(clonestr("{\"error\":\"cant get privkey\"}"));
}
} else memcpy(priv,mypriv,sizeof(priv));
btc_priv2pub(pub,priv);
init_hexbytes_noT(pubkeystr,pub,33);
PNACL_message("pubkey.%s\n",pubkeystr);
retjson = cJSON_CreateObject();
jaddstr(retjson,"btcpubkey",pubkeystr);
for (i=0; i<sizeof(addrtypes)/sizeof(*addrtypes); i++)
{
if ( btc_coinaddr(destaddr,atoi(addrtypes[i][1]),pubkeystr) == 0 )
{
item = cJSON_CreateObject();
jaddstr(item,"addr",destaddr);
if ( addrtypes[i][2] != 0 )
{
decode_hex(&addrtype,1,addrtypes[i][2]);
btc_priv2wip(wifbuf,priv,addrtype);
jaddstr(item,"wif",wifbuf);
}
jadd(retjson,addrtypes[i][0],item);
}
}
nxt64bits = nxt_priv2addr(rsaddr,pubkeystr,priv);
item = cJSON_CreateObject();
jaddstr(item,"addressRS",rsaddr);
jadd64bits(item,"address",nxt64bits);
jaddstr(item,"pubkey",pubkeystr);
jadd(retjson,"NXT",item);
return(jprint(retjson,1));
}
*/
/*INT_AND_ARRAY(pangea,newhand,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,ping,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,gotdeck,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,ready,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,encoded,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,final,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,addedfunds,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,preflop,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,decoded,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,card,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,facedown,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,faceup,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,turn,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,confirmturn,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,chat,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,action,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,showdown,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}
INT_AND_ARRAY(pangea,handsummary,senderind,params)
{
cJSON *retjson = cJSON_CreateObject();
return(jprint(retjson,1));
}*/
/*INT_AND_ARRAY(pangea,newhand,senderind,params);
INT_AND_ARRAY(pangea,ping,senderind,params);
INT_AND_ARRAY(pangea,gotdeck,senderind,params);
INT_AND_ARRAY(pangea,ready,senderind,params);
INT_AND_ARRAY(pangea,encoded,senderind,params);
INT_AND_ARRAY(pangea,final,senderind,params);
INT_AND_ARRAY(pangea,addedfunds,senderind,params);
INT_AND_ARRAY(pangea,preflop,senderind,params);
INT_AND_ARRAY(pangea,decoded,senderind,params);
INT_AND_ARRAY(pangea,card,senderind,params);
INT_AND_ARRAY(pangea,facedown,senderind,params);
INT_AND_ARRAY(pangea,faceup,senderind,params);
INT_AND_ARRAY(pangea,turn,senderind,params);
INT_AND_ARRAY(pangea,confirmturn,senderind,params);
INT_AND_ARRAY(pangea,chat,senderind,params);
INT_AND_ARRAY(pangea,action,senderind,params);
INT_AND_ARRAY(pangea,showdown,senderind,params);
INT_AND_ARRAY(pangea,handsummary,senderind,params);*/
else if ( (sp= pangea_find64(tableid,my64bits)) != 0 && (chatstr= jstr(json,"chat")) != 0 && strlen(chatstr) < 256 )
{
if ( 0 && (pm= j64bits(json,"pm")) != 0 )
{
for (i=0; i<sp->numaddrs; i++)
if ( sp->addrs[i] == pm )
break;
if ( i == sp->numaddrs )
return(clonestr("{\"error\":\"specified pm destination not at table\"}"));
} else i = -1;
pangea_sendcmd(hex,&sp->tp->hn,"chat",i,(void *)chatstr,(int32_t)strlen(chatstr)+1,pangea_ind(sp,sp->myslot),-1);
return(clonestr("{\"result\":\"chat message sent\"}"));
}
/*void _pangea_chat(uint64_t senderbits,void *buf,int32_t len,int32_t senderind)
{
PNACL_message(">>>>>>>>>>> CHAT FROM.%d %llu: (%s)\n",senderind,(long long)senderbits,(char *)buf);
}
else if ( strcmp(methodstr,"newtable") == 0 )
retstr = pangea_newtable(juint(json,"threadid"),json,plugin->nxt64bits,*(bits256 *)plugin->mypriv,*(bits256 *)plugin->mypub,plugin->transport,plugin->ipaddr,plugin->pangeaport,juint(json,"minbuyin"),juint(json,"maxbuyin"),juint(json,"rakemillis"));
else if ( sender == 0 || sender[0] == 0 )
{
if ( strcmp(methodstr,"start") == 0 )
{
strcpy(retbuf,"{\"result\":\"start issued\"}");
if ( (base= jstr(json,"base")) != 0 )
{
if ( (maxplayers= juint(json,"maxplayers")) < 2 )
maxplayers = 2;
else if ( maxplayers > CARDS777_MAXPLAYERS )
maxplayers = CARDS777_MAXPLAYERS;
if ( jstr(json,"resubmit") == 0 )
sprintf(retbuf,"{\"resubmit\":[{\"method\":\"start\"}, {\"bigblind\":\"%llu\"}, {\"ante\":\"%llu\"}, {\"rakemillis\":\"%u\"}, {\"maxplayers\":%d}, {\"minbuyin\":%d}, {\"maxbuyin\":%d}],\"pluginrequest\":\"SuperNET\",\"plugin\":\"InstantDEX\",\"method\":\"orderbook\",\"base\":\"%s\",\"exchange\":\"pangea\",\"allfields\":1}",(long long)j64bits(json,"bigblind"),(long long)j64bits(json,"ante"),juint(json,"rakemillis"),maxplayers,juint(json,"minbuyin"),juint(json,"maxbuyin"),jstr(json,"base")!=0?jstr(json,"base"):"BTCD");
else if ( pangea_start(plugin,retbuf,base,0,j64bits(json,"bigblind"),j64bits(json,"ante"),juint(json,"rakemillis"),maxplayers,juint(json,"minbuyin"),juint(json,"maxbuyin"),json) < 0 )
;
} else strcpy(retbuf,"{\"error\":\"no base specified\"}");
}
else if ( strcmp(methodstr,"status") == 0 )
retstr = pangea_status(plugin->nxt64bits,j64bits(json,"tableid"),json);
}
int32_t pangea_unzbuf(uint8_t *buf,char *hexstr,int32_t len)
{
int32_t i,j,len2;
for (len2=i=0; i<len; i+=2)
{
if ( hexstr[i] == 'Z' )
{
for (j=0; j<hexstr[i+1]-'A'; j++)
buf[len2++] = 0;
}
else buf[len2++] = _decode_hex(&hexstr[i]);
}
//char *tmp = calloc(1,len*2+1);
//init_hexbytes_noT(tmp,buf,len2);
//PostMessage("zlen %d to len2 %d\n",len,len2);
//free(tmp);
return(len2);
}
int32_t pangea_poll(uint64_t *senderbitsp,uint32_t *timestampp,union hostnet777 *hn)
{
char *jsonstr,*hexstr,*cmdstr; cJSON *json; struct cards777_privdata *priv; struct cards777_pubdata *dp; struct pangea_info *sp;
int32_t len,senderind,maxlen; uint8_t *buf;
*senderbitsp = 0;
dp = hn->client->H.pubdata, sp = dp->table;
priv = hn->client->H.privdata;
if ( hn == 0 || hn->client == 0 || dp == 0 || priv == 0 )
{
if ( Debuglevel > 2 )
PNACL_message("pangea_poll: null hn.%p %p dp.%p priv.%p\n",hn,hn!=0?hn->client:0,dp,priv);
return(-1);
}
maxlen = (int32_t)(sizeof(bits256) * dp->N*dp->N*dp->numcards);
if ( (buf= malloc(maxlen)) == 0 )
{
PNACL_message("pangea_poll: null buf\n");
return(-1);
}
if ( dp != 0 && priv != 0 && (jsonstr= queue_dequeue(&hn->client->H.Q,1)) != 0 )
{
//pangea_neworder(dp,dp->table,0,0);
//PNACL_message("player.%d GOT.(%s)\n",hn->client->H.slot,jsonstr);
if ( (json= cJSON_Parse(jsonstr)) != 0 )
{
*senderbitsp = j64bits(json,"sender");
if ( (senderind= juint(json,"myind")) < 0 || senderind >= dp->N )
{
PNACL_message("pangea_poll: illegal senderind.%d cardi.%d turni.%d (%s)\n",senderind,juint(json,"cardi"),juint(json,"turni"),jsonstr);
goto cleanup;
}
*timestampp = juint(json,"timestamp");
hn->client->H.state = juint(json,"state");
len = juint(json,"n");
cmdstr = jstr(json,"cmd");
if ( sp->myind < 0 )
{
// check for reactivation command
goto cleanup;
}
if ( cmdstr != 0 && strcmp(cmdstr,"preflop") == 0 )
{
if ( (hexstr= jstr(json,"data")) != 0 )
len = pangea_unzbuf(buf,hexstr,len);
}
else if ( (hexstr= jstr(json,"data")) != 0 && strlen(hexstr) == (len<<1) )
{
if ( len > maxlen )
{
PNACL_message("len too big for pangea_poll\n");
goto cleanup;
}
decode_hex(buf,len,hexstr);
} else if ( hexstr != 0 )
PNACL_message("len.%d vs hexlen.%ld (%s)\n",len,(long)(strlen(hexstr)>>1),hexstr);
if ( cmdstr != 0 )
{
if ( strcmp(cmdstr,"newhand") == 0 )
pangea_newhand(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"ping") == 0 )
pangea_ping(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"gotdeck") == 0 )
pangea_gotdeck(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"ready") == 0 )
pangea_ready(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"encoded") == 0 )
pangea_encoded(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"final") == 0 )
pangea_final(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"addfunds") == 0 )
pangea_addfunds(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"preflop") == 0 )
pangea_preflop(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"decoded") == 0 )
pangea_decoded(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"card") == 0 )
pangea_card(hn,json,dp,priv,buf,len,juint(json,"cardi"),senderind);
else if ( strcmp(cmdstr,"facedown") == 0 )
pangea_facedown(hn,json,dp,priv,buf,len,juint(json,"cardi"),senderind);
else if ( strcmp(cmdstr,"faceup") == 0 )
pangea_faceup(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"turn") == 0 )
pangea_turn(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"confirmturn") == 0 )
pangea_confirmturn(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"chat") == 0 )
pangea_chat(*senderbitsp,buf,len,senderind);
else if ( strcmp(cmdstr,"action") == 0 )
pangea_action(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"showdown") == 0 )
pangea_showdown(hn,json,dp,priv,buf,len,senderind);
else if ( strcmp(cmdstr,"summary") == 0 )
pangea_gotsummary(hn,json,dp,priv,buf,len,senderind);
}
cleanup:
free_json(json);
}
free_queueitem(jsonstr);
}
free(buf);
return(hn->client->H.state);
}
char *Pangea_bypass(uint64_t my64bits,uint8_t myprivkey[32],cJSON *json)
{
char *methodstr,*retstr = 0;
if ( (methodstr= jstr(json,"method")) != 0 )
{
if ( strcmp(methodstr,"turn") == 0 )
retstr = _pangea_input(my64bits,j64bits(json,"tableid"),json);
else if ( strcmp(methodstr,"status") == 0 )
retstr = _pangea_status(my64bits,j64bits(json,"tableid"),json);
else if ( strcmp(methodstr,"mode") == 0 )
retstr = _pangea_mode(my64bits,j64bits(json,"tableid"),json);
else if ( strcmp(methodstr,"buyin") == 0 )
retstr = _pangea_buyin(my64bits,j64bits(json,"tableid"),json);
else if ( strcmp(methodstr,"history") == 0 )
retstr = _pangea_history(my64bits,j64bits(json,"tableid"),json);
}
return(retstr);
}*/
/*sprintf(hex,"{\"cmd\":\"%s\",\"turni\":%d,\"myslot\":%d,\"myind\":%d,\"cardi\":%d,\"dest\":%d,\"sender\":\"%llu\",\"n\":%u,%s\"data\":\"",cmdstr,turni,priv->myslot,pangea_ind(dp->table,priv->myslot),cardi,destplayer,(long long)myinfo->myaddr.nxt64bits,(long)time(NULL),datalen,hoststr);
n = (int32_t)strlen(hex);
if ( strcmp(cmdstr,"preflop") == 0 )
{
memcpy(&hex[n],data,datalen+1);
hexlen = (int32_t)strlen(hex)+1;
}
else
if ( data != 0 && datalen != 0 )
init_hexbytes_noT(&hex[n],data,datalen);
strcat(hex,"\"}");
if ( (json= cJSON_Parse(hex)) == 0 )
{
PNACL_message("error creating json\n");
return;
}
free_json(json);
hexlen = (int32_t)strlen(hex)+1;*/
int32_t pangea_hexmsg(struct supernet_info *myinfo,struct pangea_msghdr *pm,int32_t len)
{
cJSON *argjson; char *method; bits256 tablehash; struct table_info *tp; int32_t flag = 0;
int32_t datalen; uint8_t *serialized; uint8_t tmp[sizeof(pm->sig)];
acct777_rwsig(0,(void *)&pm->sig,(void *)tmp);
memcpy(&pm->sig,tmp,sizeof(pm->sig));
datalen = len - (int32_t)sizeof(pm->sig);
serialized = (void *)((long)pm + sizeof(pm->sig));
if ( pangea_validate(pm,acct777_msgprivkey(serialized,datalen),pm->sig.pubkey) == 0 )
{
flag++;
iguana_rwbignum(0,pm->tablehash.bytes,sizeof(bits256),tablehash.bytes);
pm->tablehash = tablehash;
printf("<<<<<<<<<<<<< sigsize.%ld VALIDATED [%ld] len.%d t%u allocsize.%d (%s) [%d]\n",sizeof(pm->sig),(long)serialized-(long)pm,datalen,pm->sig.timestamp,pm->sig.allocsize,(char *)pm->serialized,serialized[datalen-1]);
if ( serialized[datalen-1] == 0 && (argjson= cJSON_Parse((char *)pm->serialized)) != 0 )
{
tablehash = jbits256(argjson,"subhash");
if ( (method= jstr(argjson,"cmd")) != 0 )
{
if ( strcmp(method,"lobby") == 0 )
{
//categoryhash = jbits256(argjson,"categoryhash");
}
else if ( strcmp(method,"host") == 0 )
{
if ( (tp= pangea_table(tablehash)) != 0 )
{
pangea_gamecreate(&tp->G,pm->sig.timestamp,pm->tablehash,argjson);
tp->G.creatorbits = pm->sig.signer64bits;
}
char str[65],str2[65]; printf("new game detected (%s) vs (%s)\n",bits256_str(str,tablehash),bits256_str(str2,pm->tablehash));
}
else if ( strcmp(method,"join") == 0 )
{
printf("JOIN.(%s)\n",jprint(argjson,0));
}
}
free_json(argjson);
} else printf("ERROR >>>>>>> (%s) cant parse\n",(char *)pm->serialized);
}
else
{
int32_t i; char str[65],str2[65];
for (i=0; i<datalen; i++)
printf("%02x",serialized[i]);
printf("<<<<<<<<<<<<< sigsize.%ld SIG ERROR [%ld] len.%d (%s + %s)\n",sizeof(pm->sig),(long)serialized-(long)pm,datalen,bits256_str(str,acct777_msgprivkey(serialized,datalen)),bits256_str(str2,pm->sig.pubkey));
}
return(flag);
}
if ( 0 && buf[len-1] == 0 && (argjson= cJSON_Parse((char *)buf)) != 0 )
{
printf("RESULT.(%s)\n",jprint(argjson,0));
free_json(argjson);
}
else if ( 0 )
{
char *method; bits256 tablehash; struct table_info *tp;
int32_t datalen; uint8_t *serialized; uint8_t tmp[sizeof(pm->sig)];
decode_hex(buf,len,result);
pm = (struct pangea_msghdr *)buf;
acct777_rwsig(0,(void *)&pm->sig,(void *)tmp);
memcpy(&pm->sig,tmp,sizeof(pm->sig));
datalen = len - (int32_t)sizeof(pm->sig);
serialized = (void *)((long)pm + sizeof(pm->sig));
char str[65]; printf("OLD pm.%p len.%d serialized.%p datalen.%d crc.%u %s\n",pm,len,serialized,datalen,calc_crc32(0,(void *)pm,len),bits256_str(str,pm->sig.pubkey));
if ( pangea_validate(pm,acct777_msgprivkey(serialized,datalen),pm->sig.pubkey) == 0 )
{
iguana_rwbignum(0,pm->tablehash.bytes,sizeof(bits256),tablehash.bytes);
pm->tablehash = tablehash;
printf("<<<<<<<<<<<<< sigsize.%ld VALIDATED [%ld] len.%d t%u allocsize.%d (%s) [%d]\n",sizeof(pm->sig),(long)serialized-(long)pm,datalen,pm->sig.timestamp,pm->sig.allocsize,(char *)pm->serialized,serialized[datalen-1]);
if ( serialized[datalen-1] == 0 && (argjson= cJSON_Parse((char *)pm->serialized)) != 0 )
{
tablehash = jbits256(argjson,"subhash");
if ( (method= jstr(argjson,"cmd")) != 0 )
{
if ( strcmp(method,"lobby") == 0 )
{
//categoryhash = jbits256(argjson,"categoryhash");
}
else if ( strcmp(method,"host") == 0 )
{
if ( (tp= pangea_table(tablehash)) != 0 )
{
pangea_gamecreate(&tp->G,pm->sig.timestamp,pm->tablehash,argjson);
tp->G.creatorbits = pm->sig.signer64bits;
}
char str[65],str2[65]; printf("new game detected (%s) vs (%s)\n",bits256_str(str,tablehash),bits256_str(str2,pm->tablehash));
}
else if ( strcmp(method,"join") == 0 )
{
printf("JOIN.(%s)\n",jprint(argjson,0));
}
}
free_json(argjson);
} else printf("ERROR >>>>>>> (%s) cant parse\n",(char *)pm->serialized);
}
else
{
int32_t i; char str[65],str2[65];
for (i=0; i<datalen; i++)
printf("%02x",serialized[i]);
printf("<<<<<<<<<<<<< sigsize.%ld SIG ERROR [%ld] len.%d (%s + %s)\n",sizeof(pm->sig),(long)serialized-(long)pm,datalen,bits256_str(str,acct777_msgprivkey(serialized,datalen)),bits256_str(str2,pm->sig.pubkey));
}
}
while ( 0 && (retstr= SuperNET_gethexmsg(IGUANA_CALLARGS,"pangea",0)) != 0 )
{
flag = 0;
if ( (retjson= cJSON_Parse(retstr)) != 0 )
{
if ( (result= jstr(retjson,"result")) != 0 )
{
len = (int32_t)strlen(result);
if ( is_hexstr(result,len) > 0 )
{
len >>= 1;
buf = malloc(len);
decode_hex(buf,len,result);
lag = pangea_hexmsg(myinfo,(struct pangea_msghdr *)buf,len,remoteaddr);
}
}
free_json(retjson);
}
free(retstr);
if ( flag == 0 )
break;
}
#endif