10#include <netinet/in.h>
14#include <openssl/sha.h>
18#include <bits/pthreadtypes.h>
30size_t build_getblocks_message(
unsigned char* buffer,
size_t buffer_size,
const unsigned char* block_locator,
size_t locator_count);
42 unsigned char hash1[SHA256_DIGEST_LENGTH];
43 unsigned char hash2[SHA256_DIGEST_LENGTH];
46 SHA256(payload, payload_len, hash1);
48 SHA256(hash1, SHA256_DIGEST_LENGTH, hash2);
51 memcpy(out, hash2, 4);
68 memset(buf, 0, buf_size);
72 unsigned int protocol_version = 70015;
73 memcpy(buf + offset, &protocol_version, 4);
77 unsigned long long services = 0ULL;
78 memcpy(buf + offset, &services, 8);
82 long long timestamp = (
long long)time(NULL);
83 memcpy(buf + offset, ×tamp, 8);
87 memset(buf + offset, 0, 8);
89 memset(buf + offset, 0, 16);
92 memcpy(buf + offset, &port, 2);
96 memset(buf + offset, 0, 8);
98 memset(buf + offset, 0, 16);
100 memcpy(buf + offset, &port, 2);
104 unsigned long long nonce = (((
unsigned long long)rand()) << 32) | rand();
105 memcpy(buf + offset, &nonce, 8);
109 const char* user_agent =
"/Satoshi:0.1.0/";
110 unsigned char user_agent_len = (
unsigned char)strlen(user_agent);
111 buf[offset] = user_agent_len;
113 memcpy(buf + offset, user_agent, user_agent_len);
114 offset += user_agent_len;
117 unsigned int start_height = 0;
118 memcpy(buf + offset, &start_height, 4);
122 unsigned char relay = 0;
139 const unsigned char* payload,
149 memset(&header, 0,
sizeof(header));
156 size_t cmd_len = strlen(command);
157 if (cmd_len >
sizeof(header.
command))
159 cmd_len =
sizeof(header.
command);
161 memcpy(header.
command, command, cmd_len);
164 header.
length = payload_len;
167 unsigned char csum[4];
172 memcpy(buf, &header,
sizeof(header));
173 memcpy(buf +
sizeof(header), payload, payload_len);
175 return sizeof(header) + payload_len;
178size_t build_getheaders_message(
unsigned char* buffer,
size_t buffer_size,
const unsigned char* block_locator,
size_t locator_count)
183 unsigned char payload[4 + 1 + (locator_count * 32) + 32];
186 uint32_t version = htonl(70015);
187 memcpy(payload, &version, 4);
194 memcpy(payload + offset, block_locator, locator_count * 32);
195 offset += locator_count * 32;
198 memset(payload + offset, 0, 32);
202 if (offset > buffer_size)
206 return build_message(buffer, buffer_size,
"getheaders", payload, offset);
211 unsigned char hash1[32];
212 SHA256(block_header, 80, hash1);
213 SHA256(hash1, 32, output_hash);
223 else if (value <= 0xffff)
225 else if (value <= 0xffffffff)
235 buffer[0] = (
unsigned char)value;
238 else if (value <= 0xffff)
241 buffer[1] = (
unsigned char)(value & 0xff);
242 buffer[2] = (
unsigned char)((value >> 8) & 0xff);
245 else if (value <= 0xffffffff)
248 buffer[1] = (
unsigned char)(value & 0xff);
249 buffer[2] = (
unsigned char)((value >> 8) & 0xff);
250 buffer[3] = (
unsigned char)((value >> 16) & 0xff);
251 buffer[4] = (
unsigned char)((value >> 24) & 0xff);
257 buffer[1] = (
unsigned char)(value & 0xff);
258 buffer[2] = (
unsigned char)((value >> 8) & 0xff);
259 buffer[3] = (
unsigned char)((value >> 16) & 0xff);
260 buffer[4] = (
unsigned char)((value >> 24) & 0xff);
261 buffer[5] = (
unsigned char)((value >> 32) & 0xff);
262 buffer[6] = (
unsigned char)((value >> 40) & 0xff);
263 buffer[7] = (
unsigned char)((value >> 48) & 0xff);
264 buffer[8] = (
unsigned char)((value >> 56) & 0xff);
273 if (
nodes[i].is_connected == 1)
282 nodes[i].operation_in_progress);
284 nodes[i].compact_blocks);
295 if (
nodes[i].is_connected == 1 && strcmp(
nodes[i].ip_address, ip_address) == 0)
307 fprintf(stderr,
"[Error] Invalid node index or node not connected.\n");
312 char log_filename[256];
313 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log",
318 size_t msg_len =
build_message(getaddr_msg,
sizeof(getaddr_msg),
"getaddr", NULL,
322 fprintf(stderr,
"[Error] Failed to build 'getaddr' message.\n");
327 ssize_t bytes_sent = send(node->
socket_fd, getaddr_msg, msg_len, 0);
331 "[Error] Failed to send 'getaddr' message: %s", strerror(errno));
342 setsockopt(node->
socket_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof(tv));
345 size_t total_bytes_received = 0;
346 ssize_t bytes_received;
352 bytes_received = recv(node->
socket_fd, buffer + total_bytes_received,
353 sizeof(buffer) - total_bytes_received - 1, 0);
354 if (bytes_received <= 0)
362 total_bytes_received += bytes_received;
366 size_t payload_len = hdr->
length;
369 const int max_retries = 1;
371 while (total_bytes_received < message_size)
374 bytes_received = recv(node->
socket_fd, buffer + total_bytes_received,
375 sizeof(buffer) - total_bytes_received - 1, 0);
376 if (bytes_received <= 0)
378 if (errno == EAGAIN || errno == EWOULDBLOCK)
381 "second while receiving inside if errno");
384 if (++retry_count >= max_retries)
387 "Max retries reached, stopping recv.");
400 total_bytes_received += bytes_received;
403 buffer[total_bytes_received] =
'\0';
408 memset(cmd_name, 0,
sizeof(cmd_name));
409 memcpy(cmd_name, hdr->
command, 12);
414 const unsigned char* payload_data = (
unsigned char*)buffer +
sizeof(
418 if (strcmp(cmd_name,
"addr") == 0)
426 "Insufficient payload length to read address count");
431 uint64_t count =
read_var_int(payload_data + offset, &offset);
440 "Address count exceeds maximum allowed: %llu", count);
444 for (uint64_t i = 0; i < count; i++)
446 if (offset + 30 > payload_len)
449 "Insufficient payload length for address entry");
455 memcpy(×tamp, payload_data + offset, 4);
456 timestamp = ntohl(timestamp);
463 struct in6_addr ip_addr;
464 memcpy(&ip_addr, payload_data + offset, 16);
469 memcpy(&port, payload_data + offset, 2);
474 char ip_str[INET6_ADDRSTRLEN];
475 inet_ntop(AF_INET6, &ip_addr, ip_str, INET6_ADDRSTRLEN);
478 const char* ip_type =
"IPv6";
479 if (IN6_IS_ADDR_V4MAPPED(&ip_addr))
481 struct in_addr ipv4_addr;
482 memcpy(&ipv4_addr, &ip_addr.s6_addr[12], 4);
483 inet_ntop(AF_INET, &ipv4_addr, ip_str, INET_ADDRSTRLEN);
488 if (strcmp(ip_type,
"IPv4") == 0 &&
is_valid_ipv4(ip_str) && !
500 "Received valid IPv4 address: %s:%u (timestamp: %u)",
501 ip_str, port, timestamp);
503 else if (strcmp(ip_type,
"IPv6") == 0)
507 "Received IPv6 address: %s:%u (timestamp: %u)",
508 ip_str, port, timestamp);
512 if (offset != payload_len)
515 "Remaining bytes after processing: %zu",
516 payload_len - offset);
543 char log_filename[256];
544 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", ip_addr);
549 if (peer_count == 0 || peers == NULL)
556 size_t payload_size = peer_count *
sizeof(
struct sockaddr_in6);
557 unsigned char* addr_payload = malloc(payload_size);
560 perror(
"malloc failed");
566 for (
int i = 0; i < peer_count; ++i)
568 struct sockaddr_in6* addr = (
struct sockaddr_in6*)&addr_payload[i *
sizeof(
569 struct sockaddr_in6)];
570 memset(addr, 0,
sizeof(
struct sockaddr_in6));
571 addr->sin6_family = AF_INET6;
572 addr->sin6_port = htons(peers[i].port);
573 addr->sin6_addr.s6_addr[10] = 0xFF;
574 addr->sin6_addr.s6_addr[11] = 0xFF;
575 inet_pton(AF_INET, peers[i].ip, &addr->sin6_addr.s6_addr[12]);
577 char ip_str[INET6_ADDRSTRLEN];
578 inet_ntop(AF_INET6, &addr->sin6_addr, ip_str, INET6_ADDRSTRLEN);
579 if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
581 struct in_addr ipv4_addr;
582 memcpy(&ipv4_addr, &addr->sin6_addr.s6_addr[12], 4);
583 inet_ntop(AF_INET, &ipv4_addr, ip_str, INET_ADDRSTRLEN);
591 size_t msg_len =
build_message(addr_msg,
sizeof(addr_msg),
"addr", addr_payload,
603 ssize_t bytes_sent = send(sockfd, addr_msg, msg_len, 0);
606 perror(
"Sending addresses failed");
611 "Successfully sent addresses");
628 memset(verack_msg, 0,
sizeof(verack_msg));
631 memset(&verack_header, 0,
sizeof(verack_header));
636 const char* cmd =
"verack";
638 size_t cmd_len = strlen(cmd);
639 if (cmd_len >
sizeof(verack_header.
command))
641 cmd_len =
sizeof(verack_header.
command);
643 memcpy(verack_header.
command, cmd, cmd_len);
649 unsigned char csum[4];
651 memcpy(&verack_header.
checksum, csum, 4);
654 memcpy(verack_msg, &verack_header,
sizeof(verack_header));
656 char log_filename[256];
657 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", ip_addr);
662 return send(sockfd, verack_msg,
sizeof(verack_header), 0);
669static ssize_t
send_pong(
int sockfd,
const unsigned char* nonce8)
672 unsigned char pong_payload[8];
673 memcpy(pong_payload, nonce8, 8);
686 fprintf(stderr,
"[Error] build_message failed for 'pong'.\n");
690 return send(sockfd, pong_msg, msg_len, 0);
696 uint64_t nonce = ((uint64_t)rand() << 32) | rand();
699 unsigned char ping_payload[8];
700 memcpy(ping_payload, &nonce,
sizeof(nonce));
714 fprintf(stderr,
"[Error] Failed to build 'ping' message.\n");
718 char log_filename[256];
719 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log",
721 ssize_t bytes_sent = send(sockfd, ping_msg, msg_len, 0);
725 "[Error] Failed to send 'ping' message: %s", strerror(errno));
730 "Sent 'ping' message with nonce: %llu", (
unsigned long long)nonce);
746 char log_filename[256];
747 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log",
750 "started peer communication with node with ip: %s", node->
ip_address);
756 setsockopt(node->
socket_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof(tv));
758 time_t last_ping_time = time(NULL);
763 ssize_t bytes_received = recv(node->
socket_fd, buffer,
sizeof(buffer) - 1, 0);
770 if (bytes_received < 0)
772 if (errno == EAGAIN || errno == EWOULDBLOCK)
775 "recv() timed out, continuing...");
780 "Recv failed: %s", strerror((errno)));
782 time_t current_time = time(NULL);
783 if (difftime(current_time, last_ping_time) >= 5)
786 last_ping_time = current_time;
791 if (bytes_received == 0)
794 "Connection closed by peer %s", node->
ip_address);
799 buffer[bytes_received] =
'\0';
801 "Received bytes: %s", buffer);
806 "[!] Received %zd bytes (less than header size 24).",
816 memset(cmd_name, 0,
sizeof(cmd_name));
817 memcpy(cmd_name, hdr->
command, 12);
820 "[!] Received %s command ",
824 size_t payload_len = hdr->
length;
825 const unsigned char* payload_data = (
const unsigned char*)buffer +
sizeof(
832 "Incomplete message; got %zd bytes, expected %zu.\n",
837 if (strcmp(cmd_name,
"ping") == 0)
840 if (payload_len == 8)
846 "Sending pong: %s\n", strerror(errno));
851 "Successfully sent pong");
857 "Ping payload length is not 8 bytes, not sending pong");
860 else if (strcmp(cmd_name,
"getaddr") == 0)
862 if (payload_len == 0)
868 "Sending addr: %s\n", strerror(errno));
873 "Successfully sent addresses");
879 "Invalid payload length for 'getaddr' command: %zu",
883 else if (strcmp(cmd_name,
"getheaders") == 0)
888 memcpy(&version, payload_data + offset, 4);
891 unsigned char start_hash[32];
892 memcpy(start_hash, payload_data + offset, 32);
895 unsigned char stop_hash[32];
896 memcpy(stop_hash, payload_data + offset, 32);
905 else if (strcmp(cmd_name,
"getblocks") == 0)
919 ssize_t bytes_sent = send(node->
socket_fd, payload, payload_len, 0);
931 else if (strcmp(cmd_name,
"inv") == 0)
938 else if (strcmp(cmd_name,
"getdata") == 0)
951 ssize_t bytes_sent = send(node->
socket_fd, data, data_len, 0);
964 else if (strcmp(cmd_name,
"sendcmpct") == 0)
967 if (payload_len == 9)
969 unsigned char fannounce = payload_data[0];
970 uint64_t cmpctversion;
971 memcpy(&cmpctversion, payload_data + 1, 8);
974 "compactblocks set to: %lu, fannounce: %u",
975 cmpctversion, fannounce);
980 "sendcmpct payload length is not 9 bytes, its: %zu",
985 else if (strcmp(cmd_name,
"feefilter") == 0)
988 if (payload_len == 8)
991 memcpy(&fee_rate, payload_data, 8);
994 "fee rate set to: %lu", fee_rate);
999 "feefilter payload length is not 8 bytes, its: %zu",
1005 time_t current_time = time(NULL);
1006 if (difftime(current_time, last_ping_time) >= 5)
1009 last_ping_time = current_time;
1021 perror(
"Failed to create thread for peer");
1025 if (pthread_detach(node->
thread) != 0)
1027 perror(
"Failed to detach thread for peer");
1036 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
1038 fprintf(stderr,
"[Error] socket creation failed: %s\n", strerror(errno));
1042 struct timeval timeout;
1044 timeout.tv_usec = 0;
1047 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout,
sizeof(timeout)) < 0)
1049 perror(
"setsockopt failed");
1054 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout,
sizeof(timeout)) < 0)
1056 perror(
"setsockopt failed");
1062 struct sockaddr_in servaddr;
1063 memset(&servaddr, 0,
sizeof(servaddr));
1064 servaddr.sin_family = AF_INET;
1067 if (inet_pton(AF_INET, ip_addr, &servaddr.sin_addr) <= 0)
1069 fprintf(stderr,
"[Error] inet_pton failed (IP '%s'): %s\n",
1070 ip_addr, strerror(errno));
1076 if (connect(sockfd, (
struct sockaddr*)&servaddr,
sizeof(servaddr)) < 0)
1078 fprintf(stderr,
"[Error] connect to %s:%d failed: %s\n",
1087 unsigned char version_payload[200];
1089 version_payload,
sizeof(version_payload));
1090 if (version_payload_len == 0)
1092 fprintf(stderr,
"[Error] build_version_payload() failed.\n");
1098 unsigned char version_msg[256];
1101 sizeof(version_msg),
1106 if (version_msg_len == 0)
1108 fprintf(stderr,
"[Error] build_message() failed for 'version'.\n");
1114 ssize_t bytes_sent = send(sockfd, version_msg, version_msg_len, 0);
1117 fprintf(stderr,
"[Error] send() of 'version' failed: %s\n", strerror(errno));
1121 printf(
"[+] Sent 'version' message (%zd bytes).\n", bytes_sent);
1123 char log_filename[256];
1124 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log",
1128 unsigned char recv_buf[2048];
1129 bool connected =
false;
1130 for (
int i = 0; i < 4; ++i)
1132 printf(
"[d] Executing %dth receive loop iteration\n", i);
1133 ssize_t n = recv(sockfd, recv_buf,
sizeof(recv_buf), 0);
1136 if (errno == EAGAIN || errno == EWOULDBLOCK)
1139 "recv() timed out, continuing...");
1142 fprintf(stderr,
"[Error] recv() failed: %s\n", strerror(errno));
1148 printf(
"[i] Peer closed the connection.\n");
1155 printf(
"[!] Received %zd bytes (less than header size 24).\n", n);
1159 printf(
"[<] Received %zd bytes.\n", n);
1168 memset(cmd_name, 0,
sizeof(cmd_name));
1169 memcpy(cmd_name, hdr->
command, 12);
1171 printf(
"[<] Received command: '%s'\n", cmd_name);
1174 size_t payload_len = hdr->
length;
1178 printf(
"[!] Incomplete message; got %zd bytes, expected %zu.\n",
1184 if (strcmp(cmd_name,
"version") == 0)
1187 ssize_t verack_sent =
send_verack(sockfd, ip_addr);
1188 if (verack_sent < 0)
1190 fprintf(stderr,
"[Error] sending verack: %s\n", strerror(errno));
1194 printf(
"[+] Sent 'verack' message.\n");
1198 else if (strcmp(cmd_name,
"verack") == 0)
1206 printf(
"[!] Unhandled command: '%s' (payload size=%u)\n",
1212 printf(
"[!] Unexpected magic bytes (0x%08X).\n", hdr->
magic);
1215 if (connected ==
true)
1219 if (
nodes[j].is_connected == 0)
1238 if (node_id < 0 || node_id >=
MAX_NODES || !
nodes[node_id].is_connected)
1240 fprintf(stderr,
"[Error] Invalid node ID or node not connected.\n");
1245 char log_filename[256];
1246 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log",
1256 if (pthread_cancel(node->
thread) != 0)
1258 perror(
"Failed to cancel thread for peer");
1262 "Successfully disconnected from node %s:%u", node->
ip_address,
1269 unsigned char prev_block[32];
1270 unsigned char merkle_root[32];
1275 memcpy(&version, header, 4);
1276 memcpy(prev_block, header + 4, 32);
1277 memcpy(merkle_root, header + 36, 32);
1278 memcpy(×tamp, header + 68, 4);
1279 memcpy(&bits, header + 72, 4);
1280 memcpy(&nonce, header + 76, 4);
1282 printf(
"Version: %u\n", version);
1283 printf(
"Previous Block Hash: ");
1284 for (
int i = 0; i < 32; i++) printf(
"%02x", prev_block[i]);
1286 printf(
"Merkle Root: ");
1287 for (
int i = 0; i < 32; i++) printf(
"%02x", merkle_root[i]);
1289 printf(
"Timestamp: %u\n", timestamp);
1290 printf(
"Bits: %u\n", bits);
1291 printf(
"Nonce: %u\n", nonce);
1301 perror(
"Failed to open headers file");
1305 while (offset + 80 <= payload_len)
1308 fwrite(payload + offset, 80, 1, file);
1321 memset(block_hash, 0, 32);
1325 fseek(file, -80, SEEK_END);
1326 fread(block_hash, 32, 1, file);
1334 fprintf(stderr,
"[Error] Invalid node index or node not connected.\n");
1339 char log_filename[256];
1340 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", node->
ip_address);
1344 int locator_count = 1;
1354 fprintf(stderr,
"[Error] Failed to build 'getheaders' message.\n");
1359 ssize_t bytes_sent = send(node->
socket_fd, getheaders_msg, msg_len, 0);
1363 "[Error] Failed to send 'getheaders' message: %s", strerror(errno));
1374 setsockopt(node->
socket_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof(tv));
1377 unsigned char buffer[4096];
1378 ssize_t bytes_received = recv(node->
socket_fd, buffer,
sizeof(buffer), 0);
1379 if (bytes_received < 0)
1382 "[Error] Failed to receive response: %s", strerror(errno));
1387 log_message(
LOG_INFO, log_filename, __FILE__,
"Received response to 'getheaders' message.");
1391 guarded_print(
"Received response to 'getheaders' message:\n");
1395void send_headers(
int idx,
const unsigned char* start_hash,
const unsigned char* stop_hash)
1399 fprintf(stderr,
"[Error] Invalid node index or node not connected.\n");
1404 char log_filename[256];
1405 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", node->
ip_address);
1411 perror(
"Failed to open headers file");
1416 unsigned char buffer[81];
1417 size_t headers_count = 0;
1418 int found_start = 0;
1419 while (fread(buffer, 80, 1, file) == 1)
1421 if (memcmp(buffer, start_hash, 32) == 0)
1431 fprintf(stderr,
"[Error] Start hash not found in headers file.\n");
1438 headers_msg[offset++] = 0;
1442 memcpy(headers_msg + offset, buffer, 80);
1444 headers_msg[offset++] = 0;
1447 if (memcmp(buffer, stop_hash, 32) == 0)
1461 strncpy(header->command,
"headers", 12);
1466 ssize_t bytes_sent = send(node->
socket_fd, headers_msg, offset, 0);
1470 "[Error] Failed to send 'headers' message: %s", strerror(errno));
1479 FILE* file = fopen(filename,
"wb");
1482 perror(
"Failed to open file for writing");
1486 fwrite(payload, 1, payload_len, file);
1493 FILE* file = fopen(filename,
"rb");
1496 perror(
"Failed to open file for reading");
1500 fseek(file, 0, SEEK_END);
1501 *payload_len = ftell(file);
1502 fseek(file, 0, SEEK_SET);
1504 unsigned char* payload = (
unsigned char*)malloc(*payload_len);
1507 perror(
"Failed to allocate memory");
1512 fread(payload, 1, *payload_len, file);
1522 fprintf(stderr,
"[Error] Invalid node index or node not connected.\n");
1527 char log_filename[256];
1528 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", node->
ip_address);
1532 int locator_count = 1;
1542 fprintf(stderr,
"[Error] Failed to build 'getblocks' message.\n");
1547 ssize_t bytes_sent = send(node->
socket_fd, getblocks_msg, msg_len, 0);
1551 "[Error] Failed to send 'getblocks' message: %s", strerror(errno));
1562 setsockopt(node->
socket_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof(tv));
1565 unsigned char buffer[32768];
1566 size_t total_bytes_received = 0;
1567 ssize_t bytes_received;
1570 while ((bytes_received = recv(node->
socket_fd, buffer + total_bytes_received,
sizeof(buffer) - total_bytes_received - 1, 0)) > 0)
1572 total_bytes_received += bytes_received;
1575 if (bytes_received < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1578 "[Error] Failed to receive response: %s", strerror(errno));
1583 log_message(
LOG_INFO, log_filename, __FILE__,
"Received response to 'getblocks' message.");
1587 guarded_print(
"Received response to 'getblocks' message:\n");
1594size_t build_getblocks_message(
unsigned char* buffer,
size_t buffer_size,
const unsigned char* block_locator,
size_t locator_count)
1599 unsigned char payload[4 + 1 + (locator_count * 32) + 32];
1602 uint32_t version = htonl(70015);
1603 memcpy(payload, &version, 4);
1610 memcpy(payload + offset, block_locator, locator_count * 32);
1611 offset += locator_count * 32;
1614 memset(payload + offset, 0, 32);
1618 if (offset > buffer_size)
1622 return build_message(buffer, buffer_size,
"getblocks", payload, offset);
1628 uint64_t count =
read_var_int(payload + offset, &offset);
1632 for (uint64_t i = 0; i < count; i++)
1634 if (offset + 36 > payload_len)
1636 guarded_print(
"Insufficient payload length for inventory entry\n");
1641 memcpy(&type, payload + offset, 4);
1644 unsigned char hash[32];
1645 memcpy(hash, payload + offset, 32);
1648 guarded_print(
"Inventory item %llu: Type: %u, Hash: ", i + 1, type);
1649 for (
int j = 0; j < 32; j++)
1660 uint64_t count =
read_var_int(payload + offset, &offset);
1662 if (count == 0 || count > 50000)
1665 "Invalid inventory count in inv message: %llu", count);
1669 unsigned char hashes[count * 32];
1670 size_t hash_count = 0;
1672 for (uint64_t i = 0; i < count; i++)
1674 if (offset + 36 > payload_len)
1677 "Insufficient payload length for inventory entry");
1682 memcpy(&type, payload + offset, 4);
1687 memcpy(hashes + (hash_count * 32), payload + offset, 32);
1704 unsigned char payload[1 + (hash_count * 36)];
1711 for (
size_t i = 0; i < hash_count; i++)
1713 uint32_t type = htonl(2);
1714 memcpy(payload + offset, &type, 4);
1716 memcpy(payload + offset, hashes + (i * 32), 32);
1721 if (offset > buffer_size)
1725 return build_message(buffer, buffer_size,
"getdata", payload, offset);
1732 fprintf(stderr,
"[Error] Invalid node index or node not connected.\n");
1736 if (hash_count == 0 || hash_count > 50000)
1738 fprintf(stderr,
"[Error] Invalid hash count. Must be between 1 and 50000.\n");
1743 char log_filename[256];
1744 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", node->
ip_address);
1751 fprintf(stderr,
"[Error] Failed to build 'getdata' message.\n");
1756 ssize_t bytes_sent = send(node->
socket_fd, getdata_msg, msg_len, 0);
1760 "[Error] Failed to send 'getdata' message: %s", strerror(errno));
1771 setsockopt(node->
socket_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof(tv));
1774 unsigned char buffer[32768];
1775 ssize_t bytes_received;
1777 while ((bytes_received = recv(node->
socket_fd, buffer,
sizeof(buffer), 0)) > 0)
1783 memset(cmd_name, 0,
sizeof(cmd_name));
1784 memcpy(cmd_name, hdr->
command, 12);
1786 if (strcmp(cmd_name,
"block") == 0)
1794 if (bytes_received < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1797 "[Error] Failed to receive block message: %s", strerror(errno));
1814size_t build_inv_message(
unsigned char* buffer,
size_t buffer_size,
const unsigned char* inv_data,
size_t inv_count)
1817 size_t payload_size = var_int_size + (inv_count * 36);
1819 printf(
"inv_count: %zu, payload_size: %zu, buffer_size: %zu\n", inv_count, payload_size, buffer_size);
1823 printf(
"Buffer size is too small: buffer_size=%zu, required=%zu\n", buffer_size,
sizeof(
bitcoin_msg_header) + payload_size);
1827 unsigned char* payload = (
unsigned char*)malloc(payload_size);
1830 printf(
"Failed to allocate memory for payload\n");
1840 for (
size_t i = 0; i < inv_count; i++)
1842 memcpy(payload + offset, inv_data + (i * 36), 36);
1845 printf(
"After copying inventory vectors: offset=%zu\n", offset);
1848 size_t message_size =
build_message(buffer, buffer_size,
"inv", payload, payload_size);
1849 printf(
"Built message size: %zu\n", message_size);
1852 return message_size;
1870 fprintf(stderr,
"[Error] Invalid node index or node not connected.\n");
1874 if (inv_count == 0 || inv_count > 50000)
1876 fprintf(stderr,
"[Error] Invalid inventory count. Must be between 1 and 50000.\n");
1881 char log_filename[256];
1882 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", node->
ip_address);
1885 size_t payload_size = var_int_size + (inv_count * 36);
1888 printf(
"inv_count: %zu, inv_msg_size: %zu\n", inv_count, inv_msg_size);
1890 unsigned char* inv_msg = (
unsigned char*)malloc(inv_msg_size);
1893 fprintf(stderr,
"[Error] Failed to allocate memory for 'inv' message.\n");
1898 printf(
"msg_len: %zu\n", msg_len);
1901 fprintf(stderr,
"[Error] Failed to build 'inv' message.\n");
1907 ssize_t bytes_sent = send(node->
socket_fd, inv_msg, msg_len, 0);
1911 "[Error] Failed to send 'inv' message: %s", strerror(errno));
1917 printf(
"Sent 'inv' message.\n");
1924 setsockopt(node->
socket_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof(tv));
1927 unsigned char buffer[32768];
1928 ssize_t bytes_received = recv(node->
socket_fd, buffer,
sizeof(buffer), 0);
1929 if (bytes_received < 0)
1932 "[Error] Failed to receive response: %s", strerror(errno));
1939 printf(
"Received response to 'inv' message.\n");
1949 memset(cmd_name, 0,
sizeof(cmd_name));
1950 memcpy(cmd_name, hdr->
command, 12);
1952 printf(
"Received command: '%s'\n", cmd_name);
1954 if (strcmp(cmd_name,
"inv") == 0)
1956 printf(
"Received 'inv' response:\n");
1961 printf(
"Unhandled command: '%s'\n", cmd_name);
1966 printf(
"Unexpected magic bytes (0x%08X).\n", hdr->
magic);
1971 printf(
"Received incomplete message.\n");
1987 uint64_t tx_count =
read_var_int(block_data + offset, &offset);
1989 printf(
"Number of transactions: %lu\n", tx_count);
1991 for (uint64_t i = 0; i < tx_count; i++)
1994 printf(
"Transaction %lu:\n", i + 1);
1997 uint32_t tx_version;
1998 memcpy(&tx_version, block_data + offset, 4);
2000 printf(
" Version: %u\n", tx_version);
2003 uint64_t input_count =
read_var_int(block_data + offset, &offset);
2004 printf(
" Number of inputs: %lu\n", input_count);
2007 for (uint64_t j = 0; j < input_count; j++)
2013 uint64_t script_len =
read_var_int(block_data + offset, &offset);
2016 offset += script_len + 4;
2020 uint64_t output_count =
read_var_int(block_data + offset, &offset);
2021 printf(
" Number of outputs: %lu\n", output_count);
2024 for (uint64_t j = 0; j < output_count; j++)
2028 memcpy(&value, block_data + offset, 8);
2030 printf(
" Value: %lu\n", value);
2033 uint64_t script_len =
read_var_int(block_data + offset, &offset);
2036 offset += script_len;
2041 memcpy(&lock_time, block_data + offset, 4);
2043 printf(
" Lock time: %u\n", lock_time);
2047void send_tx(
int idx,
const unsigned char* tx_data,
size_t tx_size)
2051 fprintf(stderr,
"[Error] Invalid node index or node not connected.\n");
2056 char log_filename[256];
2057 snprintf(log_filename,
sizeof(log_filename),
"peer_connection_%s.log", node->
ip_address);
2059 if (!tx_data || tx_size == 0)
2061 fprintf(stderr,
"[Error] Invalid transaction data.\n");
2071 strncpy(header->command,
"tx", 12);
2072 header->length =
htole32(tx_size);
2083 "[Error] Failed to send 'tx' message: %s", strerror(errno));
int is_in_private_network(const char *ip_addr)
Check if the IP address is in the private prefix (e.g.
void log_message(log_level level, const char *filename, const char *source_file, const char *format,...)
Log a message used to log a message to the console or a file.
void init_logging(const char *filename)
Initialize logging used to initialize the logging system, open and preserve the log file.
void list_connected_nodes()
Lists all connected nodes and their details.
void send_inv_and_wait(int idx, const unsigned char *inv_data, size_t inv_count)
Sends an 'inv' message to the peer.
size_t build_getblocks_message(unsigned char *buffer, size_t buffer_size, const unsigned char *block_locator, size_t locator_count)
static void compute_checksum(const unsigned char *payload, size_t payload_len, unsigned char out[4])
compute_checksum: Calculate the double-SHA256 of the payload, then copy the first 4 bytes into out[4]...
void parse_inv_message(const unsigned char *payload, size_t payload_len)
static size_t build_message(unsigned char *buf, size_t buf_size, const char *command, const unsigned char *payload, size_t payload_len)
build_message: Creates a Bitcoin P2P message (header + payload) in buf.
void save_blocks_to_file(const unsigned char *payload, size_t payload_len, const char *filename)
void send_getheaders_and_wait(int idx)
Sends a 'getheaders' message to the peer and waits for a response.
void send_getblocks_and_wait(int idx)
Sends a 'getblocks' message to the peer and waits for a response.
unsigned char * load_blocks_from_file(const char *filename, size_t *payload_len)
void * peer_communication(void *arg)
int get_idx(const char *ip_address)
Get the index of the node with the given IP address.
void send_headers(int idx, const unsigned char *start_hash, const unsigned char *stop_hash)
Sends a 'headers' message to the peer.
void send_tx(int idx, const unsigned char *tx_data, size_t tx_size)
Sends a 'tx' message to the specified node.
void decode_transactions(const unsigned char *block_data, size_t block_len)
void load_latest_known_block_hash(unsigned char *block_hash)
ssize_t send_ping(int sockfd, const char *ip_addr)
size_t build_getdata_message(unsigned char *buffer, size_t buffer_size, const unsigned char *hashes, size_t hash_count)
size_t build_getheaders_message(unsigned char *buffer, size_t buffer_size, const unsigned char *block_locator, size_t locator_count)
void initialize_node(Node *node, const char *ip, uint16_t port, int socket_fd)
size_t write_var_int(unsigned char *buf, uint64_t value)
void send_getaddr_and_wait(int idx)
Sends a 'getaddr' message to the peer and waits for a response.
static size_t build_version_payload(unsigned char *buf, size_t buf_size)
build_version_payload: Build a minimal "version" message payload.
static ssize_t send_pong(int sockfd, const unsigned char *nonce8)
send_pong: Send a "pong" message echoing the same 8-byte nonce from a "ping" payload.
void handle_inv_message(int idx, const unsigned char *payload, size_t payload_len)
void parse_headers_message(const unsigned char *payload, size_t payload_len)
size_t build_inv_message(unsigned char *buffer, size_t buffer_size, const unsigned char *inv_data, size_t inv_count)
Builds an 'inv' message.
ssize_t send_addr(int sockfd, const char *ip_addr)
send_addr: Sends the 'addr' message to the specified socket with the list of peers.
void print_block_header(const unsigned char *header)
void create_peer_thread(Node *node)
int connect_to_peer(const char *ip_addr)
Connects to a peer using the specified IP address.
static ssize_t send_verack(int sockfd, const char *ip_addr)
send_verack: Constructs a verack message with an empty payload (length = 0) and a valid 4-byte checks...
void disconnect(int node_id)
Disconnects from the node specified by the node ID.
void compute_block_hash(const unsigned char *block_header, unsigned char *output_hash)
void send_getdata_and_wait(int idx, const unsigned char *hashes, size_t hash_count)
Sends a 'getdata' message to the peer and waits for a response.
#define BITCOIN_MAINNET_PORT
#define MAX_HEADERS_COUNT
#define MAX_LOCATOR_COUNT
#define BITCOIN_MAINNET_MAGIC
Peer * get_peer_queue(int *count)
Get the peer queue.
void add_peer_to_queue(const char *ip, int port)
Add a peer to the queue.
The structure to store information about a connected peer.
int operation_in_progress
The peer structure used to store the peer information obtained by peer discovery process.
size_t read_var_int(const unsigned char *data, uint64_t *value)
Convert a 64-bit integer from network byte order to host byte order.
int is_valid_ipv4(const char *ip_str)
Check if the IP address is valid.
void guarded_print_line(const char *format,...)
Guarded print line function.
void guarded_print(const char *format,...)
Guarded print function.