예제 #1
0
/* Simple single-transacion error. */
void complain_bad_tx(struct state *state,
		     struct block *block,
		     enum protocol_ecode err,
		     const struct protocol_proof *proof,
		     const union protocol_tx *tx,
		     const struct protocol_input_ref *refs)
{
	struct protocol_pkt_complain_tx_invalid *pkt;

	switch (err) {
	case PROTOCOL_ECODE_TX_HIGH_VERSION:
	case PROTOCOL_ECODE_TX_LOW_VERSION:
	case PROTOCOL_ECODE_TX_TYPE_UNKNOWN:
	case PROTOCOL_ECODE_TX_TOO_LARGE:
	case PROTOCOL_ECODE_TX_BAD_SIG:
		break;

	case PROTOCOL_ECODE_TX_BAD_GATEWAY:
	case PROTOCOL_ECODE_TX_CROSS_SHARDS:
		assert(tx_type(tx) == TX_FROM_GATEWAY);
		break;

	case PROTOCOL_ECODE_TX_TOO_MANY_INPUTS:
		switch (tx_type(tx)) {
		case TX_NORMAL:
		case TX_TO_GATEWAY:
			break;
		case TX_FROM_GATEWAY:
		case TX_CLAIM:
			abort();
		}
		break;

	default:
		log_broken(state->log,
			   "Unknown complain_bad_tx error ");
		log_add_enum(state->log, enum protocol_ecode, err);
		abort();
	}

	log_unusual(state->log, "Block %u ", le32_to_cpu(block->hdr->depth));
	log_add_struct(state->log, struct protocol_double_sha, &block->sha);
	log_add(state->log, " invalid due to tx %u of shard %u ",
		proof->pos.txoff, le16_to_cpu(proof->pos.shard));
	log_add(state->log, " error ");
	log_add_enum(state->log, enum protocol_ecode, err);
	/* FIXME: Would be nice to log something about invalid tx! */

	pkt = tal_packet(block, struct protocol_pkt_complain_tx_invalid,
			 PROTOCOL_PKT_COMPLAIN_TX_INVALID);
	pkt->error = cpu_to_le32(err);

	tal_packet_append_proven_tx(&pkt, proof, tx, refs);

	publish_complaint(state, block, pkt, NULL);
}
예제 #2
0
/* Is this tx in the (other) shard affected by this tx? */
bool peer_wants_tx_other(const struct peer *peer, const union protocol_tx *tx)
{
	u16 shard;

	switch (tx_type(tx)) {
	case TX_FROM_GATEWAY:
		/* These only affect one shard. */
		return false;
	case TX_NORMAL:
		/* This also affects shard of output address. */
		shard = shard_of(&tx->normal.output_addr, 16);
		return peer_wants_shard(peer, shard);
	case TX_TO_GATEWAY:
	case TX_CLAIM:
		/* These only affect one shard (inputs). */
		return false;
	}
	abort();
}
예제 #3
0
파일: tx.c 프로젝트: pastcompute/pettycoin
bool find_output(const union protocol_tx *tx, u16 output_num,
		 struct protocol_address *addr, u32 *amount)
{
	const struct protocol_gateway_payment *out;

	switch (tx_type(tx)) {
	case TX_FROM_GATEWAY:
		if (output_num > le16_to_cpu(tx->from_gateway.num_outputs))
			return false;
		out = get_from_gateway_outputs(&tx->from_gateway);
		*addr = out[output_num].output_addr;
		*amount = le32_to_cpu(out[output_num].send_amount);
		return true;
	case TX_NORMAL:
		if (output_num == 0) {
			/* Spending the send_amount. */
			*addr = tx->normal.output_addr;
			*amount = le32_to_cpu(tx->normal.send_amount);
			return true;
		} else if (output_num == 1) {
			/* Spending the change. */
			get_tx_input_address(tx, addr);
			*amount = le32_to_cpu(tx->normal.change_amount);
			return true;
		}
		return false;
	case TX_CLAIM:
		if (output_num == 0) {
			get_tx_input_address(tx, addr);
			*amount = le32_to_cpu(tx->claim.amount);
			return true;
		}
		return false;
	case TX_TO_GATEWAY:
		return false;
	}
	abort();
}
예제 #4
0
파일: tx.c 프로젝트: pastcompute/pettycoin
u32 tx_amount_sent(const union protocol_tx *tx)
{
	switch (tx_type(tx)) {
	case TX_NORMAL:
		return le32_to_cpu(tx->normal.send_amount)
			+ le32_to_cpu(tx->normal.change_amount);
	case TX_FROM_GATEWAY: {
		u32 i, total = 0;
		for (i = 0; i < le16_to_cpu(tx->from_gateway.num_outputs); i++){
			le32 amount;
			amount = get_from_gateway_outputs(&tx->from_gateway)
				[i].send_amount;
			total += le32_to_cpu(amount);
		}
		return total;
	}
	case TX_TO_GATEWAY:
		return le32_to_cpu(tx->to_gateway.send_amount)
			+ le32_to_cpu(tx->to_gateway.change_amount);
	case TX_CLAIM:
		return le32_to_cpu(tx->claim.amount);
	}
	abort();
}
예제 #5
0
void json_add_tx(struct json_result *response, const char *fieldname,
		 struct state *state,
		 const union protocol_tx *tx,
		 const struct block *block,
		 unsigned int confirms)
{
	struct protocol_tx_id sha;

	json_object_start(response, fieldname);
	hash_tx(tx, &sha);
	json_add_tx_id(response, "txid", &sha);
	if (block)
		json_add_block_id(response, "block", &block->sha);
	json_add_num(response, "confirmations", confirms);
	json_add_num(response, "version", tx->hdr.version);
	json_add_num(response, "features", tx->hdr.features);

	switch (tx_type(tx)) {
	case TX_NORMAL:
		json_add_string(response, "type", "TX_NORMAL");
		json_add_pubkey(response, "input_key", &tx->normal.input_key);
		json_add_address(response, "output_addr",
				 state->test_net, &tx->normal.output_addr);
		json_add_num(response, "send_amount",
			     le32_to_cpu(tx->normal.send_amount));
		json_add_num(response, "change_amount",
			     le32_to_cpu(tx->normal.change_amount));
		json_add_signature(response, "signature",
				   &tx->normal.signature);
		json_add_inputs(response, tx);
		goto finish;
	case TX_FROM_GATEWAY:
		json_add_string(response, "type", "TX_FROM_GATEWAY");
		json_add_pubkey(response, "gateway_key",
				&tx->from_gateway.gateway_key);
		json_add_signature(response, "signature",
				   &tx->normal.signature);
		json_add_outputs(response, state, tx);
		goto finish;
	case TX_TO_GATEWAY:
		json_add_string(response, "type", "TX_TO_GATEWAY");
		json_add_pubkey(response, "input_key",
				&tx->to_gateway.input_key);
		json_add_address(response, "output_addr",
				 state->test_net,
				 &tx->to_gateway.to_gateway_addr);
		json_add_num(response, "send_amount",
			     le32_to_cpu(tx->to_gateway.send_amount));
		json_add_num(response, "change_amount",
			     le32_to_cpu(tx->to_gateway.change_amount));
		json_add_signature(response, "signature",
				   &tx->to_gateway.signature);
		json_add_inputs(response, tx);
		goto finish;
	case TX_CLAIM:
		json_add_string(response, "type", "TX_CLAIM");
		json_add_pubkey(response, "input_key", &tx->claim.input_key);
		json_add_num(response, "amount", le32_to_cpu(tx->claim.amount));
		json_add_signature(response, "claim", &tx->claim.signature);
		json_add_input(response, "input", &tx->claim.input);
		goto finish;
	}
	abort();

finish:
	json_object_end(response);
}
예제 #6
0
enum input_ecode add_pending_tx(struct state *state,
				const union protocol_tx *tx,
				const struct protocol_double_sha *sha,
				unsigned int *bad_input_num,
				bool *too_old)
{
	enum input_ecode ierr;

	/* If it's already in longest known chain, would look like
	 * doublespend so sort that out now. */
	if (txhash_gettx_ancestor(state, sha, state->longest_knowns[0]))
		return ECODE_INPUT_OK;

	/* If we already have it in pending, don't re-add. */
	if (txhash_get_pending_tx(state, sha))
		return ECODE_INPUT_OK;

	/* We check inputs for where *we* would mine it.
	 * We currently don't allow two dependent txs in the same block,
	 * so only resolve inputs in the chain. */
	ierr = check_tx_inputs(state, state->longest_knowns[0],
			       NULL, tx, bad_input_num);

	if (ierr == ECODE_INPUT_OK) {
		/* But that doesn't find doublespends in *pending*. */
		if (find_pending_doublespend(state, tx))
			ierr = ECODE_INPUT_DOUBLESPEND;
	}

	switch (ierr) {
	case ECODE_INPUT_OK:
		break;
	case ECODE_INPUT_UNKNOWN:
		/* FIXME: If we did a check_tx_inputs() which included
		 * TX_PENDING now, we might find doublespends or bad
		 * amounts already. */
		break;
	case ECODE_INPUT_BAD:
	case ECODE_INPUT_BAD_AMOUNT:
	case ECODE_INPUT_DOUBLESPEND:
	case ECODE_INPUT_CLAIM_BAD:
		log_debug(state->log, "Check tx inputs said ");
		log_add_enum(state->log, enum input_ecode, ierr);
		log_add(state->log, " for tx ");
		log_add_struct(state->log, union protocol_tx, tx);
		if (too_old)
			*too_old = false;
		return ierr;
	}

	/* We still want to transmit these to peers, just not keep them
	 * ourselves. */
	switch (tx_type(tx)) {
	case TX_NORMAL:
	case TX_TO_GATEWAY:
	case TX_CLAIM:
		if (state->require_non_gateway_tx_fee && !tx_pays_fee(tx)) {
			log_info(state->log, "Dropping feeless normal tx ");
			log_add_struct(state->log, union protocol_tx, tx);
			/* If we're ECODE_INPUT_UNKNOWN, we don't care. */
			return ECODE_INPUT_OK;
		}
		break;
	case TX_FROM_GATEWAY:
		if (state->require_gateway_tx_fee && !tx_pays_fee(tx)) {
			log_unusual(state->log, "Dropping feeless gateway tx ");
			log_add_struct(state->log, union protocol_tx, tx);
			/* If we're ECODE_INPUT_UNKNOWN, we don't care. */
			return ECODE_INPUT_OK;
		}