示例#1
0
文件: net.c 项目: aido/picocoin
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);

	log_debug("net: %s block %s",
			conn->addr_str, hexstr);

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

    if (!conn->nci->block_process(&block, &conn->msg.hdr, &buf))
    goto out;

	rc = true;

out:
	bp_block_free(&block);
	return rc;
}
示例#2
0
static void bp_json_set_new_int256(json_t *obj, const char *key, const bu256_t *i)
{
	char hexstr[(32 * 2) + 1];
	bu256_hex(hexstr, i);

	json_t *val = json_string(hexstr);
	assert(val != NULL);

	int rc = json_object_set_new(obj, key, val);
	assert(rc == 0);
}
示例#3
0
static bool spend_block(struct bp_utxo_set *uset, const struct bp_block *block,
			unsigned int height)
{
	unsigned int i;

	for (i = 0; i < block->vtx->len; i++) {
		struct bp_tx *tx;

		tx = parr_idx(block->vtx, i);
		if (!spend_tx(uset, tx, i, height)) {
			char hexstr[BU256_STRSZ];
			bu256_hex(hexstr, &tx->sha256);
			fprintf(plog, "brd: spent_block tx fail %s\n", hexstr);
			return false;
		}
	}

	return true;
}
示例#4
0
static bool process_block(const struct bp_block *block, int64_t fpos)
{
	struct blkinfo *bi = bi_new();
	bu256_copy(&bi->hash, &block->sha256);
	bp_block_copy_hdr(&bi->hdr, block);
	bi->n_file = 0;
	bi->n_pos = fpos;

	struct blkdb_reorg reorg;

	if (!blkdb_add(&db, bi, &reorg)) {
		fprintf(plog, "brd: blkdb add fail\n");
		goto err_out;
	}

	/* FIXME: support reorg */
	assert(reorg.conn == 1);
	assert(reorg.disconn == 0);

	/* if best chain, mark TX's as spent */
	if (bu256_equal(&db.best_chain->hash, &bi->hdr.sha256)) {
		if (!spend_block(&uset, block, bi->height)) {
			char hexstr[BU256_STRSZ];
			bu256_hex(hexstr, &bi->hdr.sha256);
			fprintf(plog,
				"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;
}
示例#5
0
static bool spend_block(struct bp_utxo_set *uset, const struct bp_block *block,
			unsigned int height)
{
	unsigned int i;

	if (height % 10000 == 0)
		fprintf(stderr, "chain-verf: spend block @ %u\n", height);

	for (i = 0; i < block->vtx->len; i++) {
		struct bp_tx *tx;

		tx = g_ptr_array_index(block->vtx, i);
		if (!spend_tx(uset, tx, i, height)) {
			char hexstr[BU256_STRSZ];
			bu256_hex(hexstr, &tx->sha256);
			fprintf(stderr, 
				"chain-verf: tx fail %s\n", hexstr);
			return false;
		}
	}

	return true;
}
示例#6
0
static void read_test_msg(struct blkdb *db, struct bp_utxo_set *uset,
			  const struct p2p_message *msg, int64_t fpos)
{
	assert(strncmp(msg->hdr.command, "block",
		       sizeof(msg->hdr.command)) == 0);

	struct bp_block block;
	bp_block_init(&block);

	struct const_buffer buf = { msg->data, msg->hdr.data_len };
	assert(deser_bp_block(&block, &buf) == true);
	bp_block_calc_sha256(&block);

	assert(bp_block_valid(&block) == true);

	struct blkinfo *bi = bi_new();
	bu256_copy(&bi->hash, &block.sha256);
	bp_block_copy_hdr(&bi->hdr, &block);
	bi->n_file = 0;
	bi->n_pos = fpos + P2P_HDR_SZ;

	assert(blkdb_add(db, bi) == true);

	/* if best chain, mark TX's as spent */
	if (bu256_equal(&db->hashBestChain, &bi->hdr.sha256)) {
		if (!spend_block(uset, &block, bi->height)) {
			char hexstr[BU256_STRSZ];
			bu256_hex(hexstr, &bi->hdr.sha256);
			fprintf(stderr, 
				"chain-verf: block fail %u %s\n",
				bi->height, hexstr);
			assert(!"spend_block");
		}
	}

	bp_block_free(&block);
}
示例#7
0
文件: net.c 项目: aido/picocoin
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;

	msg_vinv_init(&mv);
	msg_vinv_init(&mv_out);

	if (!deser_msg_vinv(&mv, &buf))
		goto out;

	if (log_state->debug && 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;
		}

		log_debug("net: %s inv %s %s",
			conn->addr_str, typestr, hexstr);
	}
	else if (mv.invs) {
		log_debug("net: %s inv (%zu sz)",
			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 (conn->nci->inv_block_process(&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;
}
示例#8
0
static void runtest(const char *json_base_fn, const char *ser_in_fn,
		    const char *block_in_hash, const char *tx_in_hash)
{
	/* read wallet data */
	char *json_fn = test_filename(json_base_fn);
	json_t *wallet = read_json(json_fn);
	assert(wallet != NULL);

	/* read block data containing incoming payment */
	char *fn = test_filename(ser_in_fn);
	void *data;
	size_t data_len;
	assert(bu_read_file(fn, &data, &data_len, 1 * 1024 * 1024) == true);

	struct bp_block block_in;
	bp_block_init(&block_in);
	struct const_buffer buf = { data, data_len };

	assert(deser_bp_block(&block_in, &buf) == true);
	bp_block_calc_sha256(&block_in);

	/* verify block-in data matches expected block-in hash */
	bu256_t check_hash;
	assert(hex_bu256(&check_hash, block_in_hash) == true);

	assert(bu256_equal(&block_in.sha256, &check_hash) == true);

	/* load key that has received an incoming payment */
	struct bp_key key;
	assert(bp_key_init(&key) == true);

	load_json_key(wallet, &key);

	/* load key into keyset */
	struct bp_keyset ks;
	bpks_init(&ks);

	assert(bpks_add(&ks, &key) == true);

	/* find key matches in block */
	parr *matches;
	matches = bp_block_match(&block_in, &ks);
	assert(matches != NULL);
	assert(matches->len == 1);

	struct bp_block_match *match = parr_idx(matches, 0);
	assert(match->n == 1);			/* match 2nd tx, index 1 */

	/* get matching transaction */
	struct bp_tx *tx = parr_idx(block_in.vtx, match->n);
	bp_tx_calc_sha256(tx);

	/* verify txid matches expected */
	char tx_hexstr[BU256_STRSZ];
	bu256_hex(tx_hexstr, &tx->sha256);
	assert(strcmp(tx_hexstr, tx_in_hash) == 0);

	/* verify mask matches 2nd txout (1 << 1) */
	BIGNUM tmp_mask;
	BN_init(&tmp_mask);
	BN_one(&tmp_mask);
	BN_lshift(&tmp_mask, &tmp_mask, 1);
	assert(BN_cmp(&tmp_mask, &match->mask) == 0);

	/* build merkle tree, tx's branch */
	parr *mtree = bp_block_merkle_tree(&block_in);
	assert(mtree != NULL);
	parr *mbranch = bp_block_merkle_branch(&block_in, mtree, match->n);
	assert(mbranch != NULL);

	/* verify merkle branch for tx matches expected */
	bu256_t mrk_check;
	bp_check_merkle_branch(&mrk_check, &tx->sha256, mbranch, match->n);
	assert(bu256_equal(&mrk_check, &block_in.hashMerkleRoot) == true);

	/* release resources */
	parr_free(mtree, true);
	parr_free(mbranch, true);
	BN_clear_free(&tmp_mask);
	parr_free(matches, true);
	bpks_free(&ks);
	bp_key_free(&key);
	bp_block_free(&block_in);
	json_decref(wallet);
	free(data);
	free(fn);
	free(json_fn);
}
示例#9
0
static void test_tx_valid(bool is_valid, struct bp_hashtab *input_map,
			  cstring *tx_ser, bool enforce_p2sh)
{
	struct bp_tx tx;

	bp_tx_init(&tx);

	struct const_buffer buf = { tx_ser->str, tx_ser->len };
	assert(deser_bp_tx(&tx, &buf) == true);

	if (is_valid) {
		/* checking for valid tx; !bp_tx_valid implies test fail */
		assert(bp_tx_valid(&tx) == true);
	} else {
		/* checking for invalid tx; bp_tx_valid==false implies test
		 * succeeded; no more work to do; bp_tx_valid==true
		 * implies the test will detect the invalid condition
		 * further down in the code
		 */
		if (bp_tx_valid(&tx) == false)
			goto out;
	}

	bp_tx_calc_sha256(&tx);

	unsigned int i;
	for (i = 0; i < tx.vin->len; i++) {
		struct bp_txin *txin;

		txin = parr_idx(tx.vin, i);
		assert(txin != NULL);

		cstring *scriptPubKey = bp_hashtab_get(input_map,
						       &txin->prevout);
		if (scriptPubKey == NULL) {
			if (!is_valid) {
				/* if testing tx_invalid.json, missing input
				 * is invalid, and therefore correct
				 */
				continue;
			}

			char tx_hexstr[BU256_STRSZ], hexstr[BU256_STRSZ];
			bu256_hex(tx_hexstr, &tx.sha256);
			bu256_hex(hexstr, &txin->prevout.hash);
			dump_comments();
			fprintf(stderr,
			"tx-valid: TX %s\n"
			"tx-valid: prevout (%s, %u) not found\n",
				tx_hexstr, hexstr, txin->prevout.n);

			assert(scriptPubKey != NULL);
		}

		bool rc = bp_script_verify(txin->scriptSig, scriptPubKey,
					&tx, i,
					enforce_p2sh ? SCRIPT_VERIFY_P2SH :
					SCRIPT_VERIFY_NONE, 0);
		if (rc != is_valid) {
			char tx_hexstr[BU256_STRSZ];
			bu256_hex(tx_hexstr, &tx.sha256);
			dump_comments();
			fprintf(stderr,
			"tx-valid: TX %s\n"
			"tx-valid: txin %u script verification failed\n",
				tx_hexstr, i);

			assert(rc == is_valid);
		}
	}

out:
	bp_tx_free(&tx);
}
示例#10
0
文件: block.c 项目: aido/picocoin
static void runtest(const char *json_fn_base, const char *ser_fn_base)
{
	char *fn = test_filename(json_fn_base);
	json_t *meta = read_json(fn);
	assert(json_is_object(meta));

	char *ser_fn = test_filename(ser_fn_base);
	int fd = file_seq_open(ser_fn);
	if (fd < 0) {
		perror(ser_fn);
		exit(1);
	}

	struct p2p_message msg = {};
	bool read_ok = false;
	bool rc = fread_message(fd, &msg, &read_ok);
	assert(rc);
	assert(read_ok);
	assert(!strncmp(msg.hdr.command, "block", 12));

	close(fd);

	const char *hashstr = json_string_value(json_object_get(meta, "hash"));
	assert(hashstr != NULL);

	unsigned int size = json_integer_value(json_object_get(meta, "size"));
	assert((24 + msg.hdr.data_len) == size);

	struct bp_block block;
	bp_block_init(&block);

	struct const_buffer buf = { msg.data, msg.hdr.data_len };

	rc = deser_bp_block(&block, &buf);
	assert(rc);

	cstring *gs = cstr_new_sz(100000);
	ser_bp_block(gs, &block);

	if (gs->len != msg.hdr.data_len) {
		fprintf(stderr, "gs->len %ld, msg.hdr.data_len %u\n",
			(long)gs->len, msg.hdr.data_len);
		assert(gs->len == msg.hdr.data_len);
	}
	assert(memcmp(gs->str, msg.data, msg.hdr.data_len) == 0);

	bp_block_calc_sha256(&block);

	char hexstr[BU256_STRSZ];
	bu256_hex(hexstr, &block.sha256);

	if (strcmp(hexstr, hashstr)) {
		fprintf(stderr, "block: wanted hash %s,\n       got    hash %s\n",
			hashstr, hexstr);
		assert(!strcmp(hexstr, hashstr));
	}

	rc = bp_block_valid(&block);
	assert(rc);

	bp_block_free(&block);
	cstr_free(gs, true);
	free(msg.data);
	free(fn);
	free(ser_fn);
	json_decref(meta);
}
示例#11
0
文件: tx.c 项目: Artogn/picocoin
static void runtest(const char *json_fn_base, const char *ser_fn_base)
{
	char *fn = test_filename(json_fn_base);
	json_t *meta = read_json(fn);
	assert(json_is_object(meta));

	char *ser_fn = test_filename(ser_fn_base);

	void *data = NULL;
	size_t data_len = 0;

	bool rc = bu_read_file(ser_fn, &data, &data_len, 100 * 1024 * 1024);
	assert(rc);

	const char *hashstr = json_string_value(json_object_get(meta, "hash"));
	assert(hashstr != NULL);

	unsigned int size = json_integer_value(json_object_get(meta, "size"));
	assert(data_len == size);

	struct bp_tx tx;
	bp_tx_init(&tx);

	struct const_buffer buf = { data, data_len };

	rc = deser_bp_tx(&tx, &buf);
	assert(rc);

	cstring *gs = cstr_new_sz(10000);
	ser_bp_tx(gs, &tx);

	if (gs->len != data_len) {
		fprintf(stderr, "gs->len %ld, data_len %lu\n",
			(long)gs->len, data_len);
		assert(gs->len == data_len);
	}
	assert(memcmp(gs->str, data, data_len) == 0);

	bp_tx_calc_sha256(&tx);

	char hexstr[BU256_STRSZ];
	bu256_hex(hexstr, &tx.sha256);

	if (strcmp(hexstr, hashstr)) {
		fprintf(stderr, "tx: wanted hash %s,\n    got    hash %s\n",
			hashstr, hexstr);
		assert(!strcmp(hexstr, hashstr));
	}

	assert(tx.vin->len == 1);
	assert(tx.vout->len == 2);

	struct bp_tx tx_copy;
	bp_tx_init(&tx_copy);

	bp_tx_copy(&tx_copy, &tx);
	bp_tx_calc_sha256(&tx_copy);
	assert(bu256_equal(&tx_copy.sha256, &tx.sha256) == true);

	bp_tx_free(&tx);
	bp_tx_free(&tx_copy);
	cstr_free(gs, true);
	free(data);
	free(fn);
	free(ser_fn);
	json_decref(meta);
}
示例#12
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;
}
示例#13
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;
}