Beispiel #1
0
static bool nc_msg_block(struct nc_conn *conn)
{
	struct const_buffer buf = { conn->msg.data, conn->msg.hdr.data_len };
	struct bp_block block;
	bp_block_init(&block);

	bool rc = false;

	if (!deser_bp_block(&block, &buf))
		goto out;
	bp_block_calc_sha256(&block);
	char hexstr[BU256_STRSZ];
	bu256_hex(hexstr, &block.sha256);

	if (debugging) {
		fprintf(plog, "net: %s block %s\n",
			conn->addr_str,
			hexstr);
	}

	if (!bp_block_valid(&block)) {
		fprintf(plog, "net: %s invalid block %s\n",
			conn->addr_str,
			hexstr);
		goto out;
	}

	/* check for duplicate block */
	if (blkdb_lookup(&db, &block.sha256) ||
	    have_orphan(&block.sha256))
		goto out_ok;

	struct iovec iov[2];
	iov[0].iov_base = &conn->msg.hdr;	// TODO: endian bug?
	iov[0].iov_len = sizeof(conn->msg.hdr);
	iov[1].iov_base = (void *) buf.p;	// cast away 'const'
	iov[1].iov_len = buf.len;
	size_t total_write = iov[0].iov_len + iov[1].iov_len;

	/* store current file position */
	off64_t fpos64 = lseek64(blocks_fd, 0, SEEK_CUR);
	if (fpos64 == (off64_t)-1) {
		fprintf(plog, "blocks: lseek64 failed %s\n",
			strerror(errno));
		goto out;
	}

	/* write new block to disk */
	errno = 0;
	ssize_t bwritten = writev(blocks_fd, iov, ARRAY_SIZE(iov));
	if (bwritten != total_write) {
		fprintf(plog, "blocks: write failed %s\n",
			strerror(errno));
		goto out;
	}
	/* process block */
	if (!process_block(&block, fpos64)) {
		fprintf(plog, "blocks: process-block failed\n");
		goto out;
	}

out_ok:
	rc = true;

out:
	bp_block_free(&block);
	return rc;
}
Beispiel #2
0
static bool blkdb_connect(struct blkdb *db, struct blkinfo *bi,
			  struct blkdb_reorg *reorg_info)
{
	memset(reorg_info, 0, sizeof(*reorg_info));

	if (blkdb_lookup(db, &bi->hash))
		return false;

	bool rc = false;
	BIGNUM cur_work;
	BN_init(&cur_work);

	u256_from_compact(&cur_work, bi->hdr.nBits);

	bool best_chain = false;

	/* verify genesis block matches first record */
	if (bp_hashtab_size(db->blocks) == 0) {
		if (!bu256_equal(&bi->hdr.sha256, &db->block0))
			goto out;

		/* bi->prev = NULL; */
		bi->height = 0;

		BN_copy(&bi->work, &cur_work);

		best_chain = true;
	}

	/* lookup and verify previous block */
	else {
		struct blkinfo *prev = blkdb_lookup(db, &bi->hdr.hashPrevBlock);
		if (!prev)
			goto out;

		bi->prev = prev;
		bi->height = prev->height + 1;

		if (!BN_add(&bi->work, &cur_work, &prev->work))
			goto out;

		if (BN_cmp(&bi->work, &db->best_chain->work) > 0)
			best_chain = true;
	}

	/* add to block map */
	bp_hashtab_put(db->blocks, &bi->hash, bi);

	/* if new best chain found, update pointers */
	if (best_chain) {
		struct blkinfo *old_best = db->best_chain;
		struct blkinfo *new_best = bi;

		reorg_info->old_best = old_best;

		/* likely case: new best chain has greater height */
		if (!old_best) {
			while (new_best) {
				new_best = new_best->prev;
				reorg_info->conn++;
			}
		} else {
			while (new_best &&
			       (new_best->height > old_best->height)) {
				new_best = new_best->prev;
				reorg_info->conn++;
			}
		}

		/* unlikely case: old best chain has greater height */
		while (old_best && new_best &&
		       (old_best->height > new_best->height)) {
			old_best = old_best->prev;
			reorg_info->disconn++;
		}

		/* height matches, but we are still walking parallel chains */
		while (old_best && new_best && (old_best != new_best)) {
			new_best = new_best->prev;
			reorg_info->conn++;

			old_best = old_best->prev;
			reorg_info->disconn++;
		}

		/* reorg analyzed. update database's best-chain pointer */
		db->best_chain = bi;
	}

	rc = true;

out:
	BN_clear_free(&cur_work);
	return rc;
}
Beispiel #3
0
/*
 *
struct msg_vinv {
        parr    *invs;    array of bp_inv  
};

struct bp_inv {
        uint32_t        type;
        bu256_t         hash;
};
 *
 * */
static bool nc_msg_inv(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;
	unsigned int i=0;
	
	int msg_tx, msg_block, msg_other;
		
	msg_tx = msg_block = msg_other = 0;

	msg_vinv_init(&mv);//memset
	msg_vinv_init(&mv_out);//memset

	if (!deser_msg_vinv(&mv, &buf))
		goto out;
	if (mv.invs){
		//LOG("Peer [%s] gave %d inventory vectors",conn->addr_str, mv.invs->len);
		for (i = 0;i < mv.invs->len; i++){
			struct bp_inv *inv = parr_idx(mv.invs, 0);
			switch (inv->type){
			case MSG_TX:
				msg_tx++;
				break;
			case MSG_BLOCK:
				msg_block++;
				break;
			default:
				msg_other++;
			} 
		}
		if (mv.invs->len > 0){
			LOG("Inventory vectors: msg[%d], block[%d], other[%d]",
				msg_tx, msg_block, msg_other);
		}
	}
		
	if (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;
		}

		fprintf(plog, "net: %s inv %s %s\n",
			conn->addr_str, typestr, hexstr);
	}
	else if (debugging && mv.invs) {
		fprintf(plog, "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 */
	/*declared at beginnning of function--> 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(&db, &inv->hash) &&
			    !have_orphan(&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(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;
}