Exemplo n.º 1
0
static bool wallet_eq(const struct wallet *wlt1,
		      const struct wallet *wlt2)
{
	unsigned int i;

	if (wlt1->version != wlt2->version)
		return false;

	if (wlt1->chain != wlt2->chain)
		return false;

	if (wlt1->keys->len != wlt2->keys->len)
		return false;

	for (i = 0; i < wlt1->keys->len; i++) {
		const struct bp_key *key1, *key2;

		key1 = parr_idx(wlt1->keys, i);
		key2 = parr_idx(wlt2->keys, i);

		if (!key_eq(key1, key2))
			return false;
	}

	return true;
}
Exemplo n.º 2
0
Arquivo: net.c Projeto: aido/picocoin
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(conn);
		n_gc++;
	}

	clist_free(dead);

	log_debug("net: gc'd %u connections", n_gc);
}
Exemplo n.º 3
0
bool bp_sign_sig(struct bp_keystore *ks, const struct bp_utxo *txFrom,
		 struct bp_tx *txTo, unsigned int nIn,
		 unsigned int flags, int nHashType)
{
	if (!ks || !txFrom || !txFrom->vout ||
	    !txTo || !txTo->vin || nIn >= txTo->vin->len)
		return false;

	struct bp_txin *txin = parr_idx(txTo->vin, nIn);

	if (txin->prevout.n >= txFrom->vout->len)
		return false;
	struct bp_txout *txout = parr_idx(txFrom->vout,
						   txin->prevout.n);

	return bp_script_sign(ks, txout->scriptPubKey, txTo, nIn, nHashType);
}
Exemplo n.º 4
0
static void dump_comments(void)
{
	unsigned int i;
	for (i = 0; i < comments->len; i++) {
		fprintf(stderr, "tx-valid cmt: %s\n",
			(char *)parr_idx(comments, i));
	}
}
Exemplo n.º 5
0
/**
 *struct msg_addr {
        parr    *addrs;         //bp_address array
};
 */
static bool nc_msg_addr(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);/* just a memset 0*/

	if (!deser_msg_addr(conn->protover, &ma, &buf))
		goto out;

	unsigned int i;
	time_t cutoff = time(NULL) - (7 * 24 * 60 * 60);
	if (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++;
		}
		fprintf(plog, "net: %s addr(%zu addresses, %u old)\n",
			conn->addr_str, ma.addrs->len, old);
	}
	/* ignore ancient addresses */
        if (conn->protover < CADDR_TIME_VERSION){
                LOG("all addresses rejected because protover < CADDR_TIME_VERSION");
                goto out_ok;
        }
	/* feed addresses to peer manager */
	int l_cnt = 0;
	for (i = 0; i < ma.addrs->len; i++) {
		struct bp_address *addr = parr_idx(ma.addrs, i);
		if (addr->nTime > cutoff){
			l_cnt++;
			peerman_add_addr(conn->nci->peers, addr, false);
		}
	}
	LOG("number of addresses added from peer:%d", l_cnt);

out_ok:
	rc = true;

out:
	msg_addr_free(&ma);
	return rc;
}
Exemplo n.º 6
0
static void runtest(const char *ser_fn_base)
{
	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);

	struct bitc_block block;
	bitc_block_init(&block);

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

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

	unsigned int n_tx, n_out;
	for (n_tx = 0; n_tx < block.vtx->len; n_tx++) {
		struct bitc_tx *tx = parr_idx(block.vtx, n_tx);

		for (n_out = 0; n_out < tx->vout->len; n_out++) {
			struct bitc_txout *txout;

			txout = parr_idx(tx->vout, n_out);
			test_txout(txout);
		}
	}

	bitc_block_free(&block);
	free(msg.data);
	free(ser_fn);
}
Exemplo n.º 7
0
Arquivo: net.c Projeto: aido/picocoin
static bool nc_msg_addr(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 (log_state->debug) {
		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++;
		}
		log_debug("net: %s addr(%zu addresses, %u old)",
			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;
}
Exemplo n.º 8
0
bool bp_verify_sig(const struct bp_utxo *txFrom, const struct bp_tx *txTo,
		   unsigned int nIn, unsigned int flags, int nHashType)
{
	if (!txFrom || !txFrom->vout || !txFrom->vout->len ||
	    !txTo || !txTo->vin || !txTo->vin->len ||
	    (txTo->vin->len <= nIn))
		return false;

	struct bp_txin *txin = parr_idx(txTo->vin, nIn);
	if (txin->prevout.n >= txFrom->vout->len)
		return false;

	struct bp_txout *txout = parr_idx(txFrom->vout,
						   txin->prevout.n);
	if (!txout)
		return false;

	return bp_script_verify(txin->scriptSig, txout->scriptPubKey,
				txTo, nIn, flags, nHashType);
}
Exemplo n.º 9
0
Arquivo: net.c Projeto: aido/picocoin
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;
}
Exemplo n.º 10
0
struct wallet_account *account_byname(struct wallet *wlt, const char *name)
{
	if (!wlt || !wlt->accounts || !wlt->accounts->len)
		return NULL;

	unsigned int i;
	for (i = 0; i < wlt->accounts->len; i++) {
		struct wallet_account *acct = parr_idx(wlt->accounts, i);
		if (!strcmp(name, acct->name->str))
			return acct;
	}

	return NULL;
}
Exemplo n.º 11
0
bool bp_tx_match(const struct bp_tx *tx, const struct bp_keyset *ks)
{
	if (!tx || !tx->vout || !ks)
		return false;

	unsigned int i;
	for (i = 0; i < tx->vout->len; i++) {
		struct bp_txout *txout;

		txout = parr_idx(tx->vout, i);
		if (bp_txout_match(txout, ks))
			return true;
	}

	return false;
}
Exemplo n.º 12
0
bool CheckSequence(const unsigned int nSequence, const struct bp_tx *txTo, unsigned int nIn)
{
	const struct bp_txin *txin = parr_idx(txTo->vin, nIn);

	// Relative lock times are supported by comparing the passed
	// in operand to the sequence number of the input.
	const int64_t txToSequence = (int64_t)txin->nSequence;

	// Fail if the transaction's version number is not set high
	// enough to trigger BIP 68 rules.
	if (txTo->nVersion < 2)
		return false;

	// Sequence numbers with their most significant bit set are not
	// consensus constrained. Testing that the transaction's sequence
	// number do not have this bit set prevents using this property
	// to get around a CHECKSEQUENCEVERIFY check.
	if (txToSequence & SEQUENCE_LOCKTIME_DISABLE_FLAG)
		return false;

	// Mask off any bits that do not have consensus-enforced meaning
	// before doing the integer comparisons
	const uint32_t nLockTimeMask = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK;
	const int64_t txToSequenceMasked = txToSequence & nLockTimeMask;
	const uint64_t nSequenceMasked = nSequence & nLockTimeMask;

	// There are two kinds of nSequence: lock-by-blockheight
	// and lock-by-blocktime, distinguished by whether
	// nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
	//
	// We want to compare apples to apples, so fail the script
	// unless the type of nSequenceMasked being tested is the same as
	// the nSequenceMasked in the transaction.
	if (!(
		(txToSequenceMasked <  SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked <  SEQUENCE_LOCKTIME_TYPE_FLAG) ||
		(txToSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG)
	)) {
		return false;
	}

	// Now that we know we're comparing apples-to-apples, the
	// comparison is a simple numeric one.
	if (nSequenceMasked > txToSequenceMasked)
		return false;

	return true;
}
Exemplo n.º 13
0
static void output_json_vout(json_t *obj)
{
	json_t *arr = json_array();
	assert(arr != NULL);

	int rc = json_object_set_new(obj, "vout", arr);
	assert(rc == 0);

	if (!tx.vout)
		return;

	unsigned int i;
	for (i = 0; i < tx.vout->len; i++) {
		struct bp_txout *txout = parr_idx(tx.vout, i);
		output_json_txout(arr, txout, i);
	}
}
Exemplo n.º 14
0
void msg_headers_free(struct msg_headers *mh)
{
	if (!mh)
		return;

	if (mh->headers) {
		unsigned int i;

		for (i = 0; i < mh->headers->len; i++) {
			struct bp_block *block;

			block = parr_idx(mh->headers, i);
			bp_block_free(block);
		}

		parr_free(mh->headers, true);
		mh->headers = NULL;
	}
}
Exemplo n.º 15
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;
}
Exemplo n.º 16
0
Arquivo: net.c Projeto: aido/picocoin
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;
}
Exemplo n.º 17
0
bool bp_tx_match_mask(BIGNUM *mask, const struct bp_tx *tx,
		      const struct bp_keyset *ks)
{
	if (!tx || !tx->vout || !ks || !mask)
		return false;

	BN_zero(mask);

	unsigned int i;
	for (i = 0; i < tx->vout->len; i++) {
		struct bp_txout *txout;

		txout = parr_idx(tx->vout, i);
		if (bp_txout_match(txout, ks))
			BN_set_bit(mask, i);
	}

	return true;
}
Exemplo n.º 18
0
parr *bp_block_match(const struct bp_block *block,
			  const struct bp_keyset *ks)
{
	if (!block || !block->vtx || !ks)
		return NULL;

	parr *arr = parr_new(block->vtx->len, bbm_free);
	if (!arr)
		return NULL;

	BIGNUM tmp_mask;
	BN_init(&tmp_mask);

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

		tx = parr_idx(block->vtx, n);
		if (!bp_tx_match_mask(&tmp_mask, tx, ks))
			goto err_out;

		if (!BN_is_zero(&tmp_mask)) {
			struct bp_block_match *match;

			match = bbm_new();
			match->n = n;
			BN_copy(&match->mask, &tmp_mask);

			parr_add(arr, match);
		}
	}

	BN_clear_free(&tmp_mask);
	return arr;

err_out:
	BN_clear_free(&tmp_mask);
	parr_free(arr, true);
	return NULL;
}
Exemplo n.º 19
0
cstring *ser_msg_addr(unsigned int protover, const struct msg_addr *ma)
{
	cstring *s = cstr_new(NULL);

	if (!ma || !ma->addrs || !ma->addrs->len) {
		ser_varlen(s, 0);
		return s;
	}

	ser_varlen(s, ma->addrs->len);

	unsigned int i;
	for (i = 0; i < ma->addrs->len; i++) {
		struct bp_address *addr;

		addr = parr_idx(ma->addrs, i);

		ser_bp_addr(s, protover, addr);
	}

	return s;
}
Exemplo n.º 20
0
cstring *ser_msg_headers(const struct msg_headers *mh)
{
	cstring *s = cstr_new(NULL);

	if (!mh || !mh->headers || !mh->headers->len) {
		ser_varlen(s, 0);
		return s;
	}

	ser_varlen(s, mh->headers->len);

	unsigned int i;
	for (i = 0; i < mh->headers->len; i++) {
		struct bp_block *block;

		block = parr_idx(mh->headers, i);

		ser_bp_block(s, block);
	}

	return s;
}
Exemplo n.º 21
0
cstring *ser_msg_vinv(const struct msg_vinv *mv)
{
	cstring *s = cstr_new(NULL);

	if (!mv || !mv->invs || !mv->invs->len) {
		ser_varlen(s, 0);
		return s;
	}

	ser_varlen(s, mv->invs->len);

	unsigned int i;
	for (i = 0; i < mv->invs->len; i++) {
		struct bp_inv *inv;

		inv = parr_idx(mv->invs, i);

		ser_bp_inv(s, inv);
	}

	return s;
}
Exemplo n.º 22
0
cstring *wallet_new_address(struct wallet *wlt)
{
	struct hd_path_seg hdpath[] = {
		{ 44, true },	// BIP 44
		{ 0, true },	// chain: BTC
		{ 0, true },	// acct#
		{ 0, false },	// change?
		{ 0, false },	// key index
	};

	struct wallet_account *acct = account_byname(wlt, wlt->def_acct->str);
	if (!acct)
		return NULL;

	// patch HD path based on account settings
	hdpath[2].index = acct->acct_idx;
	hdpath[4].index = acct->next_key_idx;

	assert(wlt->hdmaster && (wlt->hdmaster->len > 0));
	struct hd_extended_key *master = parr_idx(wlt->hdmaster, 0);
	assert(master != NULL);

	struct hd_extended_key child;
	hd_extended_key_init(&child);

	if (!hd_derive(&child, master, hdpath, ARRAY_SIZE(hdpath))) {
		hd_extended_key_free(&child);
		return NULL;
	}

	acct->next_key_idx++;

	cstring *rs = bp_pubkey_get_address(&child.key,wlt->chain->addr_pubkey);

	hd_extended_key_free(&child);

	return rs;
}
Exemplo n.º 23
0
static void nc_conns_gc(struct net_child_info *nci, bool free_all)
{
	clist *dead = NULL;
	unsigned int n_gc = 0;
        
	/*nr of dead connections*/
	size_t nr_dead = 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);
	}
        
	nr_dead = clist_length( dead );
	
	if (nr_dead){
		LOG("Nr of dead connections:%d\n", nr_dead);
	}

	/* 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(conn);
		n_gc++;
	}

	clist_free(dead);

	if (debugging)
		fprintf(plog, "net: gc'd %u connections\n", n_gc);
}
Exemplo n.º 24
0
bool CheckLockTime(const unsigned int nLockTime, const struct bp_tx *txTo, unsigned int nIn)
{
	// There are two kinds of nLockTime: lock-by-blockheight
	// and lock-by-blocktime, distinguished by whether
	// nLockTime < LOCKTIME_THRESHOLD.
	//
	// We want to compare apples to apples, so fail the script
	// unless the type of nLockTime being tested is the same as
	// the nLockTime in the transaction.
	if (!(
		(txTo->nLockTime <  LOCKTIME_THRESHOLD && nLockTime <  LOCKTIME_THRESHOLD) ||
		(txTo->nLockTime >= LOCKTIME_THRESHOLD && nLockTime >= LOCKTIME_THRESHOLD)
	))
		return false;

	// Now that we know we're comparing apples-to-apples, the
	// comparison is a simple numeric one.
	if (nLockTime > (int64_t)txTo->nLockTime)
		return false;

	// Finally the nLockTime feature can be disabled and thus
	// CHECKLOCKTIMEVERIFY bypassed if every txin has been
	// finalized by setting nSequence to maxint. The
	// transaction would be allowed into the blockchain, making
	// the opcode ineffective.
	//
	// Testing if this vin is not final is sufficient to
	// prevent this condition. Alternatively we could test all
	// inputs, but testing just this input minimizes the data
	// required to prove correct CHECKLOCKTIMEVERIFY execution.
	struct bp_txin *txin = parr_idx(txTo->vin, nIn);

	if (SEQUENCE_FINAL == txin->nSequence)
		return false;

	return true;
}
Exemplo n.º 25
0
static void stack_copy(parr *dest, const parr *src)
{
	unsigned int i;
	for (i = 0; i < src->len; i++)
		stack_push(dest, parr_idx(src, i));
}
Exemplo n.º 26
0
Arquivo: net.c Projeto: 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;
}
Exemplo n.º 27
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);
}
Exemplo n.º 28
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);
}
Exemplo n.º 29
0
bool bp_script_sign(struct bp_keystore *ks, const cstring *fromPubKey,
		    const struct bp_tx *txTo, unsigned int nIn,
		    int nHashType)
{
	if (!txTo || !txTo->vin || nIn >= txTo->vin->len)
		return false;

	struct bp_txin *txin = parr_idx(txTo->vin, nIn);

	/* get signature hash */
	bu256_t hash;
	bp_tx_sighash(&hash, fromPubKey, txTo, nIn, nHashType);

	/* match fromPubKey against templates, to find what pubkey[hashes]
	 * are required for signing
	 */
	struct bscript_addr addrs;
	if (!bsp_addr_parse(&addrs, fromPubKey->str, fromPubKey->len))
		return false;

	cstring *scriptSig = cstr_new_sz(64);
	bool rc = false;
	bu160_t key_id;
	struct buffer *kbuf;

	/* sign, based on script template matched above */
	switch (addrs.txtype) {
	case TX_PUBKEY:
		kbuf = addrs.pub->data;
		bu_Hash160((unsigned char *)&key_id, kbuf->p, kbuf->len);

		if (!sign1(&key_id, ks, &hash, nHashType, scriptSig))
			goto out;
		break;

	case TX_PUBKEYHASH:
		kbuf = addrs.pubhash->data;
		memcpy(&key_id, kbuf->p, kbuf->len);

		if (!sign1(&key_id, ks, &hash, nHashType, scriptSig))
			goto out;
		if (!bkeys_pubkey_append(ks, &key_id, scriptSig))
			goto out;
		break;

	case TX_SCRIPTHASH:		/* TODO; not supported yet */
	case TX_MULTISIG:
		goto out;

	case TX_NONSTANDARD:		/* unknown script type, cannot sign */
		goto out;
	}

	if (txin->scriptSig)
		cstr_free(txin->scriptSig, true);
	txin->scriptSig = scriptSig;
	scriptSig = NULL;
	rc = true;

out:
	if (scriptSig)
		cstr_free(scriptSig, true);
	bsp_addr_free(&addrs);
	return rc;
}
Exemplo n.º 30
0
void bp_tx_sigserializer(cstring *s, const cstring *scriptCode,
			const struct bp_tx *txTo, unsigned int nIn,
			int nHashType)
{
    const bool fAnyoneCanPay = (!!(nHashType & SIGHASH_ANYONECANPAY));
    const bool fHashSingle = ((nHashType & 0x1f) == SIGHASH_SINGLE);
    const bool fHashNone = ((nHashType & 0x1f) == SIGHASH_NONE);

    /** Serialize txTo */
    // Serialize nVersion
    ser_u32(s, txTo->nVersion);

    // Serialize vin
    unsigned int nInputs = fAnyoneCanPay ? 1 : txTo->vin->len;
    ser_varlen(s, nInputs);

	unsigned int nInput;
	for (nInput = 0; nInput < nInputs; nInput++) {
	    /** Serialize an input of txTo */
	    // In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized
		if (fAnyoneCanPay)
			nInput = nIn;

	    struct bp_txin *txin = parr_idx(txTo->vin, nInput);

	    // Serialize the prevout
	    ser_bp_outpt(s, &txin->prevout);

		// Serialize the script
		if (nInput != nIn)
			// Blank out other inputs' signatures
			ser_varlen(s, (int)0);
		else if (scriptCode == NULL)
		    cstr_append_c(s, 0);
		else {
			/** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */
			struct const_buffer it = { scriptCode->str, scriptCode->len };
			struct const_buffer itBegin = it;
			struct bscript_op op;
			unsigned int nCodeSeparators = 0;

			struct bscript_parser bp;
			bsp_start(&bp, &it);

			while (bsp_getop(&op, &bp)) {
				if (op.op == OP_CODESEPARATOR)
				    nCodeSeparators++;
			}
			ser_varlen(s, scriptCode->len - nCodeSeparators);

			it = itBegin;
			bsp_start(&bp, &it);

			while (bsp_getop(&op, &bp)) {
			    if (op.op == OP_CODESEPARATOR) {
					ser_bytes(s, itBegin.p, it.p - itBegin.p - 1);
					itBegin  = it;
			    }
			}

			if (itBegin.p != scriptCode->str + scriptCode->len)
			    ser_bytes(s, itBegin.p, it.p - itBegin.p);
		}

		// Serialize the nSequence
		if ((nInput != nIn) && (fHashSingle || fHashNone))
			// let the others update at will
			ser_u32(s, (int)0);
		else
			ser_u32(s, txin->nSequence);
	}

    // Serialize vout
    unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? (nIn + 1) : txTo->vout->len);
    ser_varlen(s, nOutputs);

	unsigned int nOutput;
    for (nOutput = 0; nOutput < nOutputs; nOutput++) {
		struct bp_txout *txout = parr_idx(txTo->vout, nOutput);
		if (fHashSingle && (nOutput != nIn))
			// Do not lock-in the txout payee at other indices as txin;
			bp_txout_set_null(txout);

		ser_bp_txout(s, txout);
    }
    // Serialize nLockTime
    ser_u32(s, txTo->nLockTime);
}