Esempio n. 1
0
CoinKey hash160_to_CoinKey(const uint160& hash_value, ICoinOption* profile)
{
	CoinRawAddress raddr;
	raddr.AddrType = profile->PubkeyStart;
	raddr.hash160 = hash_value;
	raddr.nChecksum = 0;
	uint256 h256 = double_sha256(&raddr, sizeof(BYTE)+sizeof(ripemd160));
	raddr.nChecksum = *(UINT32*)&h256;
	return raddr;
}
static ERL_NIF_TERM dsha256_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    ErlNifBinary bin;
    if (!enif_inspect_binary(env, argv[0], &bin))
        return enif_make_badarg(env);
    
    ERL_NIF_TERM ret;
    unsigned char *final_hash = enif_make_new_binary(env, 32, &ret);
    double_sha256(bin.data, bin.size, final_hash);
    reverse32(final_hash, final_hash);
    
    return ret;
}
static ERL_NIF_TERM tree_pair_dsha256_hash_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    ErlNifBinary bin1, bin2;
    if (!enif_inspect_binary(env, argv[0], &bin1) || bin1.size != 32 || !enif_inspect_binary(env, argv[1], &bin2) || bin2.size != 32)
        return enif_make_badarg(env);
    
    ERL_NIF_TERM ret;
    unsigned char in[64];
    unsigned char *final_hash = enif_make_new_binary(env, 32, &ret);
    reverse32(&in[0], bin1.data);
    reverse32(&in[32], bin2.data);
    double_sha256(in, 64, final_hash);
    reverse32(final_hash, final_hash);
    
    return ret;
}
Esempio n. 4
0
	void net_process(const std::function<void(std::string)>& disconnect) {
		while (true) {
			struct bitcoin_msg_header header;
			if (read_all((char*)&header, sizeof(header)) != sizeof(header))
				return disconnect("failed to read message header");

			if (header.magic != BITCOIN_MAGIC)
				return disconnect("invalid magic bytes");

			struct timeval start_read;
			gettimeofday(&start_read, NULL);

			header.length = le32toh(header.length);
			if (header.length > 5000000)
				return disconnect("got message too large");

			auto msg = std::make_shared<std::vector<unsigned char> > (sizeof(struct bitcoin_msg_header) + uint32_t(header.length));
			if (read_all((char*)&(*msg)[sizeof(struct bitcoin_msg_header)], header.length) != int(header.length))
				return disconnect("failed to read message");

			unsigned char fullhash[32];
			double_sha256(&(*msg)[sizeof(struct bitcoin_msg_header)], fullhash, header.length);
			if (memcmp((char*)fullhash, header.checksum, sizeof(header.checksum)))
				return disconnect("got invalid message checksum");

			if (!strncmp(header.command, "version", strlen("version"))) {
				if (connected != 0)
					return disconnect("got invalid version");
				connected = 1;

				if (header.length < sizeof(struct bitcoin_version_start))
					return disconnect("got short version");
				struct bitcoin_version_start *their_version = (struct bitcoin_version_start*) &(*msg)[sizeof(struct bitcoin_msg_header)];

				printf("%s Protocol version %u\n", host.c_str(), le32toh(their_version->protocol_version));

				struct bitcoin_version_with_header version_msg;
				version_msg.version.start.timestamp = htole64(time(0));
				memcpy(((char*)&version_msg.version.end.user_agent) + 27, location, 7);
				static_assert(BITCOIN_UA_LENGTH == 27 + 7 + 2 /* 27 + 7 + '/' + '\0' */, "BITCOIN_UA changed in header but file not updated");

				prepare_message("version", (unsigned char*)&version_msg, sizeof(struct bitcoin_version));
				do_send_bytes((char*)&version_msg, sizeof(struct bitcoin_version_with_header));

				struct bitcoin_msg_header verack_header;
				prepare_message("verack", (unsigned char*)&verack_header, 0);
				do_send_bytes((char*)&verack_header, sizeof(struct bitcoin_msg_header));

				continue;
			} else if (!strncmp(header.command, "verack", strlen("verack"))) {
				if (connected != 1)
					return disconnect("got invalid verack");
				connected = 2;
				continue;
			}

			if (connected != 2)
				return disconnect("got non-version, non-verack before version+verack");

			if (!strncmp(header.command, "ping", strlen("ping"))) {
				memcpy(&header.command, "pong", sizeof("pong"));
				memcpy(&(*msg)[0], &header, sizeof(struct bitcoin_msg_header));
				do_send_bytes((char*)&(*msg)[0], sizeof(struct bitcoin_msg_header) + header.length);
				continue;
			} else if (!strncmp(header.command, "inv", strlen("inv"))) {
				std::lock_guard<std::mutex> lock(seen_mutex);

				try {
					std::set<std::vector<unsigned char> > setRequestBlocks;
					std::set<std::vector<unsigned char> > setRequestTxn;

					std::vector<unsigned char>::const_iterator it = msg->begin();
					it += sizeof(struct bitcoin_msg_header);
					uint64_t count = read_varint(it, msg->end());
					if (count > 50000)
						return disconnect("inv count > MAX_INV_SZ");

					uint32_t MSG_TX = htole32(1);
					uint32_t MSG_BLOCK = htole32(2);

					for (uint64_t i = 0; i < count; i++) {
						move_forward(it, 4 + 32, msg->end());
						std::vector<unsigned char> hash(it-32, it);

						const uint32_t type = (*(it-(1+32)) << 24) | (*(it-(2+32)) << 16) | (*(it-(3+32)) << 8) | *(it-(4+32));
						if (type == MSG_TX) {
							if (!txnAlreadySeen.insert(hash).second)
								continue;
							setRequestTxn.insert(hash);
						} else if (type == MSG_BLOCK) {
							if (!blocksAlreadySeen.insert(hash).second)
								continue;
							setRequestBlocks.insert(hash);
						} else
							return disconnect("unknown inv type");
					}

					if (setRequestBlocks.size()) {
						std::vector<unsigned char> getdataMsg;
						std::vector<unsigned char> invCount = varint(setRequestBlocks.size());
						getdataMsg.reserve(sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestBlocks.size()*36);

						getdataMsg.insert(getdataMsg.end(), sizeof(struct bitcoin_msg_header), 0);
						getdataMsg.insert(getdataMsg.end(), invCount.begin(), invCount.end());

						for (auto& hash : setRequestBlocks) {
							getdataMsg.insert(getdataMsg.end(), (unsigned char*)&MSG_BLOCK, ((unsigned char*)&MSG_BLOCK) + 4);
							getdataMsg.insert(getdataMsg.end(), hash.begin(), hash.end());
						}

						prepare_message("getdata", (unsigned char*)&getdataMsg[0], invCount.size() + setRequestBlocks.size()*36);
						do_send_bytes((char*)&getdataMsg[0], sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestBlocks.size()*36);

						for (auto& hash : setRequestBlocks) {
							struct timeval tv;
							gettimeofday(&tv, NULL);
							for (unsigned int i = 0; i < hash.size(); i++)
								printf("%02x", hash[hash.size() - i - 1]);
							printf(" requested from %s at %lu\n", host.c_str(), uint64_t(tv.tv_sec) * 1000 + uint64_t(tv.tv_usec) / 1000);
						}
					}

					if (setRequestTxn.size()) {
						std::vector<unsigned char> getdataMsg;
						std::vector<unsigned char> invCount = varint(setRequestTxn.size());
						getdataMsg.reserve(sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestTxn.size()*36);

						getdataMsg.insert(getdataMsg.end(), sizeof(struct bitcoin_msg_header), 0);
						getdataMsg.insert(getdataMsg.end(), invCount.begin(), invCount.end());

						for (const std::vector<unsigned char>& hash : setRequestTxn) {
							getdataMsg.insert(getdataMsg.end(), (unsigned char*)&MSG_TX, ((unsigned char*)&MSG_TX) + 4);
							getdataMsg.insert(getdataMsg.end(), hash.begin(), hash.end());
						}

						prepare_message("getdata", (unsigned char*)&getdataMsg[0], invCount.size() + setRequestTxn.size()*36);
						do_send_bytes((char*)&getdataMsg[0], sizeof(struct bitcoin_msg_header) + invCount.size() + setRequestTxn.size()*36);
					}
				} catch (read_exception) {
					return disconnect("failed to process inv");
				}
				continue;
			}

			memcpy(&(*msg)[0], &header, sizeof(struct bitcoin_msg_header));
			if (!strncmp(header.command, "block", strlen("block"))) {
				provide_block(this, msg, start_read);
			} else if (!strncmp(header.command, "tx", strlen("tx"))) {
				provide_transaction(this, msg);
			}
		}
	}
Esempio n. 5
0
int main(int argc, char** argv) {
	if (argc != 2 || strlen(argv[1]) != 7) {
		printf("USAGE %s 7-char-LOCATION\n", argv[0]);
		return -1;
	}
	location = argv[1];

	int blockonly_fd, txes_fd, new_fd;
	struct sockaddr_in6 addr;

	fd_set twofds;
	FD_ZERO(&twofds);

	if ((blockonly_fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0 ||
		     (txes_fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
		printf("Failed to create socket\n");
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin6_family = AF_INET6;
	addr.sin6_addr = in6addr_any;
	addr.sin6_port = htons(8334);

	int reuse = 1;

	if (setsockopt(blockonly_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) ||
			bind(blockonly_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0 ||
			listen(blockonly_fd, 3) < 0) {
		printf("Failed to bind 8334: %s\n", strerror(errno));
		return -1;
	}

	addr.sin6_port = htons(8335);
	if (setsockopt(txes_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) ||
			bind(txes_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0 ||
			listen(txes_fd, 3) < 0) {
		printf("Failed to bind 8335: %s\n", strerror(errno));
		return -1;
	}

	std::mutex list_mutex;
	std::set<P2PConnection*> blockSet;
	std::set<P2PConnection*> txesSet;
	std::set<P2PConnection*> localSet;

	std::function<void (P2PConnection*, std::shared_ptr<std::vector<unsigned char> >&, struct timeval)> relayBlock =
		[&](P2PConnection* from, std::shared_ptr<std::vector<unsigned char>> & bytes, struct timeval start_recv) {
			struct timeval start_send, finish_send;
			gettimeofday(&start_send, NULL);

			if (bytes->size() < 80)
				return;
			std::vector<unsigned char> fullhash(32);
			getblockhash(fullhash, *bytes, sizeof(struct bitcoin_msg_header));

			{
				std::lock_guard<std::mutex> lock(list_mutex);
				std::set<P2PConnection*> *set;
				if (localSet.count(from))
					set = &blockSet;
				else
					set = &localSet;
				for (auto it = set->begin(); it != set->end(); it++) {
					if (!(*it)->getDisconnectFlags())
						(*it)->receive_block(fullhash, bytes);
				}
			}

			gettimeofday(&finish_send, NULL);
			for (unsigned int i = 0; i < fullhash.size(); i++)
				printf("%02x", fullhash[fullhash.size() - i - 1]);
			printf(" BLOCK %lu %s %s %u / %u TIMES: %ld %ld\n", uint64_t(start_send.tv_sec) * 1000 + uint64_t(start_send.tv_usec) / 1000, from->host.c_str(),
					localSet.count(from) ? "LOCALRELAY" : "REMOTEP2P", (unsigned)bytes->size(), (unsigned)bytes->size(),
					int64_t(start_send.tv_sec - start_recv.tv_sec)*1000 + (int64_t(start_send.tv_usec) - start_recv.tv_usec)/1000,
					int64_t(finish_send.tv_sec - start_send.tv_sec)*1000 + (int64_t(finish_send.tv_usec) - start_send.tv_usec)/1000);
		};
	std::function<void (P2PConnection*, std::shared_ptr<std::vector<unsigned char> >&)> relayTx =
		[&](P2PConnection* from, std::shared_ptr<std::vector<unsigned char> >& bytes) {
			std::vector<unsigned char> fullhash(32);
			double_sha256(&(*bytes)[sizeof(struct bitcoin_msg_header)], &fullhash[0], bytes->size() - sizeof(struct bitcoin_msg_header));

			std::lock_guard<std::mutex> lock(list_mutex);
			std::set<P2PConnection*> *set;
			if (localSet.count(from))
				set = &txesSet;
			else
				set = &localSet;
			for (auto it = set->begin(); it != set->end(); it++) {
				if (!(*it)->getDisconnectFlags())
					(*it)->receive_transaction(fullhash, bytes);
			}
		};

	printf("Awaiting connections\n");

	while (true) {
		FD_SET(blockonly_fd, &twofds);
		FD_SET(txes_fd, &twofds);
		struct timeval timeout;
		timeout.tv_sec = 30;
		timeout.tv_usec = 0;

		if (select(FD_SETSIZE, &twofds, NULL, NULL, &timeout) < 0) {
			printf("Failed to select (%s)\n", strerror(errno));
			return -1;
		}

		socklen_t addr_size = sizeof(addr);
		std::string localhost("::ffff:127.0.0.1/");
		std::string droppostfix(".uptimerobot.com");
		if (FD_ISSET(blockonly_fd, &twofds)) {
			if ((new_fd = accept(blockonly_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
				printf("Failed to accept\n");
				return -1;
			}

			std::string host = gethostname(&addr);
			if (host.length() > droppostfix.length() && !host.compare(host.length() - droppostfix.length(), droppostfix.length(), droppostfix))
				close(new_fd);
			else {
				std::lock_guard<std::mutex> lock(list_mutex);
				P2PConnection *relay = new P2PConnection(new_fd, host, relayBlock, relayTx);
				if (!host.compare(0, localhost.size(), localhost))
					localSet.insert(relay);
				else
					blockSet.insert(relay);
			}
		}
		if (FD_ISSET(txes_fd, &twofds)) {
			if ((new_fd = accept(txes_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
				printf("Failed to accept\n");
				return -1;
			}

			std::string host = gethostname(&addr);
			if (host.length() > droppostfix.length() && !host.compare(host.length() - droppostfix.length(), droppostfix.length(), droppostfix))
				close(new_fd);
			else {
				std::lock_guard<std::mutex> lock(list_mutex);
				P2PConnection *relay = new P2PConnection(new_fd, host, relayBlock, relayTx);
				if (!host.compare(0, localhost.size(), localhost))
					localSet.insert(relay);
				else {
					blockSet.insert(relay);
					txesSet.insert(relay);
				}
			}
		}

		std::lock_guard<std::mutex> lock(list_mutex);
		for (auto it = blockSet.begin(); it != blockSet.end();) {
			if ((*it)->getDisconnectFlags() & DISCONNECT_COMPLETE) {
				auto rm = it++; auto item = *rm;
				txesSet.erase(item);
				blockSet.erase(rm);
				delete item;
			} else
				it++;
		}
		for (auto it = localSet.begin(); it != localSet.end();) {
			if ((*it)->getDisconnectFlags() & DISCONNECT_COMPLETE) {
				auto rm = it++; auto item = *rm;
				localSet.erase(rm);
				delete item;
			} else
				it++;
		}
		fprintf(stderr, "Have %lu local connection(s), %lu block connection(s) and %lu txes conenction(s)\n", localSet.size(), blockSet.size() - txesSet.size(), txesSet.size());
	}
}