BitLab 0.1.0
BitLab: A Browser for the Bitcoin P2P Network and Blockchain
Loading...
Searching...
No Matches
peer_connection.c
Go to the documentation of this file.
1#include "peer_connection.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <unistd.h>
7#include <sys/types.h>
8#include <sys/socket.h>
9#include <arpa/inet.h>
10#include <netinet/in.h>
11#include <time.h>
12#include <errno.h>
13#include <stdint.h> // for uint64_t, etc.
14#include <openssl/sha.h> // For SHA-256
15#include <pthread.h>
16#include <sys/time.h>
17#include <stdbool.h>
18#include <bits/pthreadtypes.h>
19
20#include "peer_queue.h"
21#include "utils.h"
22#include "log.h"
23#include "ip.h"
24
25// Global array to hold connected nodes
27
28void parse_inv_message(const unsigned char* payload, size_t payload_len);
29void handle_inv_message(int idx, const unsigned char* payload, size_t payload_len);
30size_t build_getblocks_message(unsigned char* buffer, size_t buffer_size, const unsigned char* block_locator, size_t locator_count);
31size_t write_var_int(unsigned char* buf, uint64_t value);
32void decode_transactions(const unsigned char* block_data, size_t block_len);
33
39static void compute_checksum(const unsigned char* payload, size_t payload_len,
40 unsigned char out[4])
41{
42 unsigned char hash1[SHA256_DIGEST_LENGTH];
43 unsigned char hash2[SHA256_DIGEST_LENGTH];
44
45 // First SHA-256
46 SHA256(payload, payload_len, hash1);
47 // Second SHA-256
48 SHA256(hash1, SHA256_DIGEST_LENGTH, hash2);
49
50 // Copy first 4 bytes to out
51 memcpy(out, hash2, 4);
52}
53
60static size_t build_version_payload(unsigned char* buf, size_t buf_size)
61{
62 // We need at least 86 bytes for a minimal version message
63 if (buf_size < 86)
64 {
65 return 0;
66 }
67
68 memset(buf, 0, buf_size);
69 size_t offset = 0;
70
71 // (1) protocol version (int32_t)
72 unsigned int protocol_version = 70015;
73 memcpy(buf + offset, &protocol_version, 4);
74 offset += 4;
75
76 // (2) services (uint64_t) - set to 0
77 unsigned long long services = 0ULL;
78 memcpy(buf + offset, &services, 8);
79 offset += 8;
80
81 // (3) timestamp (int64_t) - current epoch
82 long long timestamp = (long long)time(NULL);
83 memcpy(buf + offset, &timestamp, 8);
84 offset += 8;
85
86 // (4) addr_recv (26 bytes)
87 memset(buf + offset, 0, 8); // services
88 offset += 8;
89 memset(buf + offset, 0, 16); // IP
90 offset += 16;
91 unsigned short port = htons(BITCOIN_MAINNET_PORT);
92 memcpy(buf + offset, &port, 2);
93 offset += 2;
94
95 // (5) addr_from (26 bytes) - same approach
96 memset(buf + offset, 0, 8);
97 offset += 8;
98 memset(buf + offset, 0, 16);
99 offset += 16;
100 memcpy(buf + offset, &port, 2);
101 offset += 2;
102
103 // (6) nonce (8 bytes) - random
104 unsigned long long nonce = (((unsigned long long)rand()) << 32) | rand();
105 memcpy(buf + offset, &nonce, 8);
106 offset += 8;
107
108 // (7) user agent (var_str)
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;
112 offset += 1;
113 memcpy(buf + offset, user_agent, user_agent_len);
114 offset += user_agent_len;
115
116 // (8) start_height (int32_t) - let’s set 0 for demo
117 unsigned int start_height = 0;
118 memcpy(buf + offset, &start_height, 4);
119 offset += 4;
120
121 // (9) relay (bool) for version >= 70001; set to 0
122 unsigned char relay = 0;
123 buf[offset] = relay;
124 offset += 1;
125
126 return offset; // total payload size
127}
128
135static size_t build_message(
136 unsigned char* buf,
137 size_t buf_size,
138 const char* command,
139 const unsigned char* payload,
140 size_t payload_len)
141{
142 if (buf_size < (sizeof(bitcoin_msg_header) + payload_len))
143 {
144 return 0;
145 }
146
147 // Prepare the header
148 bitcoin_msg_header header;
149 memset(&header, 0, sizeof(header));
150
152
153 // Zero out the command field, then copy up to 12 bytes
154 memset(header.command, 0, sizeof(header.command));
155 {
156 size_t cmd_len = strlen(command);
157 if (cmd_len > sizeof(header.command))
158 {
159 cmd_len = sizeof(header.command);
160 }
161 memcpy(header.command, command, cmd_len);
162 }
163
164 header.length = payload_len;
165
166 // Compute the checksum of the payload
167 unsigned char csum[4];
168 compute_checksum(payload, payload_len, csum);
169 memcpy(&header.checksum, csum, 4);
170
171 // Copy header into buf, then the payload
172 memcpy(buf, &header, sizeof(header));
173 memcpy(buf + sizeof(header), payload, payload_len);
174
175 return sizeof(header) + payload_len;
176}
177
178size_t build_getheaders_message(unsigned char* buffer, size_t buffer_size, const unsigned char* block_locator, size_t locator_count)
179{
180 if (buffer_size < sizeof(bitcoin_msg_header) + 37)
181 return 0;
182
183 unsigned char payload[4 + 1 + (locator_count * 32) + 32];
184
185 // Set protocol version (4 bytes)
186 uint32_t version = htonl(70015);
187 memcpy(payload, &version, 4);
188
189 // Set block locator count (var_int encoding)
190 size_t offset = 4;
191 offset += write_var_int(payload + offset, locator_count);
192
193 // Copy block locator hashes
194 memcpy(payload + offset, block_locator, locator_count * 32);
195 offset += locator_count * 32;
196
197 // Set hash_stop (32 bytes of zeros for max 2000 headers)
198 memset(payload + offset, 0, 32);
199 offset += 32;
200
201 // Ensure buffer is large enough
202 if (offset > buffer_size)
203 return 0;
204
205 // Build final message
206 return build_message(buffer, buffer_size, "getheaders", payload, offset);
207}
208
209void compute_block_hash(const unsigned char* block_header, unsigned char* output_hash)
210{
211 unsigned char hash1[32];
212 SHA256(block_header, 80, hash1); // First SHA-256
213 SHA256(hash1, 32, output_hash); // Second SHA-256
214}
215
216size_t write_var_int(unsigned char* buffer, uint64_t value)
217{
218 if (buffer == NULL)
219 {
220 // Calculate the size of the var_int encoding
221 if (value < 0xfd)
222 return 1;
223 else if (value <= 0xffff)
224 return 3;
225 else if (value <= 0xffffffff)
226 return 5;
227 else
228 return 9;
229 }
230
231 log_message(LOG_DEBUG, BITLAB_LOG, __FILE__, "write_var_int: buffer=%p, value=%lu", (void*)buffer, value);
232
233 if (value < 0xfd)
234 {
235 buffer[0] = (unsigned char)value;
236 return 1;
237 }
238 else if (value <= 0xffff)
239 {
240 buffer[0] = 0xfd;
241 buffer[1] = (unsigned char)(value & 0xff);
242 buffer[2] = (unsigned char)((value >> 8) & 0xff);
243 return 3;
244 }
245 else if (value <= 0xffffffff)
246 {
247 buffer[0] = 0xfe;
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);
252 return 5;
253 }
254 else
255 {
256 buffer[0] = 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);
265 return 9;
266 }
267}
268
270{
271 for (int i = 0; i < MAX_NODES; ++i)
272 {
273 if (nodes[i].is_connected == 1)
274 {
275 guarded_print_line("Node %d:", i);
276 guarded_print_line(" IP Address: %s", nodes[i].ip_address);
277 guarded_print_line(" Port: %u", nodes[i].port);
278 guarded_print_line(" Socket FD: %d", nodes[i].socket_fd);
279 guarded_print_line(" Thread ID: %lu", nodes[i].thread);
280 guarded_print_line(" Is Connected: %d", nodes[i].is_connected);
281 guarded_print_line(" Is operation in progress: %d",
282 nodes[i].operation_in_progress);
283 guarded_print_line(" Compact blocks: %lu",
284 nodes[i].compact_blocks);
285 guarded_print_line(" Fee_rate: %lu",
286 nodes[i].fee_rate);
287 }
288 }
289}
290
291int get_idx(const char* ip_address)
292{
293 for (int i = 0; i < MAX_NODES; ++i)
294 {
295 if (nodes[i].is_connected == 1 && strcmp(nodes[i].ip_address, ip_address) == 0)
296 {
297 return i;
298 }
299 }
300 return -1;
301}
302
304{
305 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
306 {
307 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
308 return;
309 }
310
311 Node* node = &nodes[idx];
312 char log_filename[256];
313 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
314 node->ip_address);
315
316 // Build the 'getaddr' message
317 unsigned char getaddr_msg[sizeof(bitcoin_msg_header)];
318 size_t msg_len = build_message(getaddr_msg, sizeof(getaddr_msg), "getaddr", NULL,
319 0);
320 if (msg_len == 0)
321 {
322 fprintf(stderr, "[Error] Failed to build 'getaddr' message.\n");
323 return;
324 }
325
326 // Send the 'getaddr' message
327 ssize_t bytes_sent = send(node->socket_fd, getaddr_msg, msg_len, 0);
328 if (bytes_sent < 0)
329 {
330 log_message(LOG_INFO, log_filename, __FILE__,
331 "[Error] Failed to send 'getaddr' message: %s", strerror(errno));
332 return;
333 }
334
335 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getaddr' message.");
336 node->operation_in_progress = 1;
337
338 // Wait for 10 seconds for a response
339 struct timeval tv;
340 tv.tv_sec = 3;
341 tv.tv_usec = 0;
342 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
343
344 char buffer[32768];
345 size_t total_bytes_received = 0;
346 ssize_t bytes_received;
347
348 // Receive the message in parts
349 while (total_bytes_received < sizeof(bitcoin_msg_header))
350 {
351 log_message(LOG_INFO, log_filename, __FILE__, "first while receiving");
352 bytes_received = recv(node->socket_fd, buffer + total_bytes_received,
353 sizeof(buffer) - total_bytes_received - 1, 0);
354 if (bytes_received <= 0)
355 {
356 log_message(LOG_INFO, log_filename, __FILE__, "Recv 1 failed: %s",
357 strerror(errno));
358 node->is_connected = 0;
359 node->operation_in_progress = 0;
360 return;
361 }
362 total_bytes_received += bytes_received;
363 }
364
366 size_t payload_len = hdr->length;
367 size_t message_size = sizeof(bitcoin_msg_header) + payload_len;
368 int retry_count = 0;
369 const int max_retries = 1;
370
371 while (total_bytes_received < message_size)
372 {
373 log_message(LOG_INFO, log_filename, __FILE__, "second while receiving");
374 bytes_received = recv(node->socket_fd, buffer + total_bytes_received,
375 sizeof(buffer) - total_bytes_received - 1, 0);
376 if (bytes_received <= 0)
377 {
378 if (errno == EAGAIN || errno == EWOULDBLOCK)
379 {
380 log_message(LOG_INFO, log_filename, __FILE__,
381 "second while receiving inside if errno");
382 // Resource temporarily unavailable, continue receiving
383
384 if (++retry_count >= max_retries)
385 {
386 log_message(LOG_WARN, log_filename, __FILE__,
387 "Max retries reached, stopping recv.");
388 node->is_connected = 0;
389 node->operation_in_progress = 0;
390 break;
391 }
392 continue;
393 }
394 log_message(LOG_INFO, log_filename, __FILE__, "Recv failed: %s",
395 strerror(errno));
396 node->is_connected = 0;
397 node->operation_in_progress = 0;
398 return;
399 }
400 total_bytes_received += bytes_received;
401 }
402
403 buffer[total_bytes_received] = '\0'; // Null-terminate the received data
404
405 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
406 {
407 char cmd_name[13];
408 memset(cmd_name, 0, sizeof(cmd_name));
409 memcpy(cmd_name, hdr->command, 12);
410
411 log_message(LOG_INFO, log_filename, __FILE__, "[!] Received %s command ",
412 cmd_name);
413
414 const unsigned char* payload_data = (unsigned char*)buffer + sizeof(
416
417
418 if (strcmp(cmd_name, "addr") == 0)
419 {
420 size_t offset = 0;
421
422 // Check if the payload length is sufficient to read the count of address entries
423 if (payload_len < 1)
424 {
425 log_message(LOG_WARN, log_filename, __FILE__,
426 "Insufficient payload length to read address count");
427 return;
428 }
429
430 // Read the count of address entries (var_int)
431 uint64_t count = read_var_int(payload_data + offset, &offset);
432
433 // Log the count of address entries
434 log_message(LOG_INFO, log_filename, __FILE__, "Address count: %llu", count);
435
436 // Ensure count does not exceed the maximum allowed entries
437 if (count > 1000)
438 {
439 log_message(LOG_WARN, log_filename, __FILE__,
440 "Address count exceeds maximum allowed: %llu", count);
441 return;
442 }
443
444 for (uint64_t i = 0; i < count; i++)
445 {
446 if (offset + 30 > payload_len)
447 {
448 log_message(LOG_WARN, log_filename, __FILE__,
449 "Insufficient payload length for address entry");
450 return;
451 }
452
453 // Read timestamp (4 bytes)
454 uint32_t timestamp;
455 memcpy(&timestamp, payload_data + offset, 4);
456 timestamp = ntohl(timestamp);
457 offset += 4;
458
459 // Read services (8 bytes, skip for now)
460 offset += 8;
461
462 // Read IP address (16 bytes)
463 struct in6_addr ip_addr;
464 memcpy(&ip_addr, payload_data + offset, 16);
465 offset += 16;
466
467 // Read port (2 bytes)
468 uint16_t port;
469 memcpy(&port, payload_data + offset, 2);
470 port = ntohs(port);
471 offset += 2;
472
473 // Convert IP to string
474 char ip_str[INET6_ADDRSTRLEN];
475 inet_ntop(AF_INET6, &ip_addr, ip_str, INET6_ADDRSTRLEN);
476
477 // Determine if the address is IPv4-mapped or IPv6
478 const char* ip_type = "IPv6";
479 if (IN6_IS_ADDR_V4MAPPED(&ip_addr))
480 {
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);
484 ip_type = "IPv4";
485 }
486
487 // Check if it's a valid IPv4 address
488 if (strcmp(ip_type, "IPv4") == 0 && is_valid_ipv4(ip_str) && !
489 is_in_private_network(ip_str))
490 {
491 // Guarded print of the IP address and port
492 guarded_print_line("Valid IPv4 Peer: %s:%u (timestamp: %u)", ip_str,
493 port, timestamp);
494
495 // Add to peer queue
496 add_peer_to_queue(ip_str, port);
497
498 // Log the result if valid
499 log_message(LOG_INFO, log_filename, __FILE__,
500 "Received valid IPv4 address: %s:%u (timestamp: %u)",
501 ip_str, port, timestamp);
502 }
503 else if (strcmp(ip_type, "IPv6") == 0)
504 {
505 // Log the IPv6 addresses if needed
506 log_message(LOG_INFO, log_filename, __FILE__,
507 "Received IPv6 address: %s:%u (timestamp: %u)",
508 ip_str, port, timestamp);
509 }
510 }
511
512 if (offset != payload_len)
513 {
514 log_message(LOG_WARN, log_filename, __FILE__,
515 "Remaining bytes after processing: %zu",
516 payload_len - offset);
517 }
518 }
519 }
520 else
521 {
522 log_message(LOG_WARN, log_filename, __FILE__,
523 "else hdr->magic ");
524 }
525
526 node->operation_in_progress = 0;
527}
528
541ssize_t send_addr(int sockfd, const char* ip_addr)
542{
543 char log_filename[256];
544 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", ip_addr);
545
546 int peer_count;
547 Peer* peers = get_peer_queue(&peer_count);
548
549 if (peer_count == 0 || peers == NULL)
550 {
551 guarded_print_line("[Error] No peers available to send");
552 return -1;
553 }
554
555 // Allocate memory for address payload (IPv4 to IPv6-mapped)
556 size_t payload_size = peer_count * sizeof(struct sockaddr_in6);
557 unsigned char* addr_payload = malloc(payload_size);
558 if (!addr_payload)
559 {
560 perror("malloc failed");
561 free(peers);
562 return -1;
563 }
564
565 // Populate address payload with peer data (IPv6-mapped addresses for IPv4)
566 for (int i = 0; i < peer_count; ++i)
567 {
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]);
576
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))
580 {
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);
584 }
585 log_message(LOG_INFO, log_filename, __FILE__, "Sending address: %s:%d", ip_str,
586 peers[i].port);
587 }
588
589 // Prepare message buffer
590 unsigned char addr_msg[sizeof(bitcoin_msg_header) + payload_size];
591 size_t msg_len = build_message(addr_msg, sizeof(addr_msg), "addr", addr_payload,
592 payload_size);
593
594 if (msg_len == 0)
595 {
596 guarded_print_line("Failed to build 'addr' message.");
597 free(peers);
598 free(addr_payload);
599 return -1;
600 }
601
602 // Send the 'addr' message
603 ssize_t bytes_sent = send(sockfd, addr_msg, msg_len, 0);
604 if (bytes_sent < 0)
605 {
606 perror("Sending addresses failed");
607 }
608 else
609 {
610 log_message(LOG_INFO, log_filename, __FILE__,
611 "Successfully sent addresses");
612 }
613
614 free(peers);
615 free(addr_payload);
616
617 return bytes_sent;
618}
619
625static ssize_t send_verack(int sockfd, const char* ip_addr)
626{
627 unsigned char verack_msg[sizeof(bitcoin_msg_header)];
628 memset(verack_msg, 0, sizeof(verack_msg));
629
630 bitcoin_msg_header verack_header;
631 memset(&verack_header, 0, sizeof(verack_header));
632 verack_header.magic = BITCOIN_MAINNET_MAGIC;
633
634 // "verack" as a 12-byte command (zero-padded)
635 {
636 const char* cmd = "verack";
637 memset(verack_header.command, 0, sizeof(verack_header.command));
638 size_t cmd_len = strlen(cmd);
639 if (cmd_len > sizeof(verack_header.command))
640 {
641 cmd_len = sizeof(verack_header.command);
642 }
643 memcpy(verack_header.command, cmd, cmd_len);
644 }
645
646 verack_header.length = 0; // no payload
647
648 // Checksum for empty payload => double-SHA256("") => first 4 bytes
649 unsigned char csum[4];
650 compute_checksum(NULL, 0, csum);
651 memcpy(&verack_header.checksum, csum, 4);
652
653 // Copy to buffer
654 memcpy(verack_msg, &verack_header, sizeof(verack_header));
655
656 char log_filename[256];
657 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", ip_addr);
658 log_message(LOG_INFO, log_filename, __FILE__,
659 "sent verack");
660 // log_to_file('test.log', 'sent verack');
661 // Send to peer
662 return send(sockfd, verack_msg, sizeof(verack_header), 0);
663}
664
669static ssize_t send_pong(int sockfd, const unsigned char* nonce8)
670{
671 // Build an 8-byte payload containing the same nonce
672 unsigned char pong_payload[8];
673 memcpy(pong_payload, nonce8, 8);
674
675 // Create the message buffer
676 unsigned char pong_msg[sizeof(bitcoin_msg_header) + 8];
677 size_t msg_len = build_message(
678 pong_msg,
679 sizeof(pong_msg),
680 "pong",
681 pong_payload,
682 8
683 );
684 if (msg_len == 0)
685 {
686 fprintf(stderr, "[Error] build_message failed for 'pong'.\n");
687 return -1;
688 }
689
690 return send(sockfd, pong_msg, msg_len, 0);
691}
692
693ssize_t send_ping(int sockfd, const char* ip_addr)
694{
695 // Generate an 8-byte nonce
696 uint64_t nonce = ((uint64_t)rand() << 32) | rand();
697
698 // Prepare the ping payload (8 bytes)
699 unsigned char ping_payload[8];
700 memcpy(ping_payload, &nonce, sizeof(nonce));
701
702 // Prepare the complete message (header + payload)
703 unsigned char ping_msg[sizeof(bitcoin_msg_header) + sizeof(ping_payload)];
704 size_t msg_len = build_message(
705 ping_msg,
706 sizeof(ping_msg),
707 "ping",
708 ping_payload,
709 sizeof(ping_payload)
710 );
711
712 if (msg_len == 0)
713 {
714 fprintf(stderr, "[Error] Failed to build 'ping' message.\n");
715 return -1;
716 }
717
718 char log_filename[256];
719 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
720 ip_addr);
721 ssize_t bytes_sent = send(sockfd, ping_msg, msg_len, 0);
722 if (bytes_sent < 0)
723 {
724 log_message(LOG_INFO, log_filename, __FILE__,
725 "[Error] Failed to send 'ping' message: %s", strerror(errno));
726 return -1;
727 }
728
729 log_message(LOG_INFO, log_filename, __FILE__,
730 "Sent 'ping' message with nonce: %llu", (unsigned long long)nonce);
731 return bytes_sent;
732}
733
734void initialize_node(Node* node, const char* ip, uint16_t port, int socket_fd)
735{
736 snprintf(node->ip_address, sizeof(node->ip_address), "%s", ip);
737 node->port = port;
738 node->socket_fd = socket_fd;
739 node->is_connected = 1; // Mark as connected
740}
741
742void* peer_communication(void* arg)
743{
744 Node* node = (Node*)arg;
745
746 char log_filename[256];
747 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
748 node->ip_address);
749 log_message(LOG_INFO, log_filename, __FILE__,
750 "started peer communication with node with ip: %s", node->ip_address);
751
752 char buffer[2048];
753 struct timeval tv;
754 tv.tv_sec = 5; // 5 seconds timeout for recv
755 tv.tv_usec = 0;
756 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
757
758 time_t last_ping_time = time(NULL);
759
760 while (node->is_connected)
761 {
762 // Check the magic
763 ssize_t bytes_received = recv(node->socket_fd, buffer, sizeof(buffer) - 1, 0);
764
765 // Wait while other operation is in progress e.g. getaddr
766 while (node->operation_in_progress)
767 {
768 sleep(1);
769 }
770 if (bytes_received < 0)
771 {
772 if (errno == EAGAIN || errno == EWOULDBLOCK)
773 {
774 log_message(LOG_WARN, log_filename, __FILE__,
775 "recv() timed out, continuing...");
776 }
777 else
778 {
779 log_message(LOG_INFO, log_filename, __FILE__,
780 "Recv failed: %s", strerror((errno)));
781 }
782 time_t current_time = time(NULL);
783 if (difftime(current_time, last_ping_time) >= 5)
784 {
785 send_ping(node->socket_fd, node->ip_address);
786 last_ping_time = current_time;
787 }
788
789 continue;
790 }
791 if (bytes_received == 0)
792 {
793 log_message(LOG_INFO, log_filename, __FILE__,
794 "Connection closed by peer %s", node->ip_address);
795 node->is_connected = 0;
796 break;
797 }
798
799 buffer[bytes_received] = '\0'; // Null-terminate the received data
800 log_message(LOG_INFO, log_filename, __FILE__,
801 "Received bytes: %s", buffer);
802 // If we have at least a full header, parse it
803 if (bytes_received < (ssize_t)sizeof(bitcoin_msg_header))
804 {
805 log_message(LOG_INFO, log_filename, __FILE__,
806 "[!] Received %zd bytes (less than header size 24).",
807 bytes_received);
808 continue;
809 }
810
811 // Cast to a header
813 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
814 {
815 char cmd_name[13];
816 memset(cmd_name, 0, sizeof(cmd_name));
817 memcpy(cmd_name, hdr->command, 12);
818
819 log_message(LOG_INFO, log_filename, __FILE__,
820 "[!] Received %s command ",
821 cmd_name);
822
823 // Determine the payload length & pointer
824 size_t payload_len = hdr->length;
825 const unsigned char* payload_data = (const unsigned char*)buffer + sizeof(
827
828 // In real code, you’d handle partial messages if n < header+payload
829 if (bytes_received < (ssize_t)(sizeof(bitcoin_msg_header) + payload_len))
830 {
831 log_message(LOG_INFO, log_filename, __FILE__,
832 "Incomplete message; got %zd bytes, expected %zu.\n",
833 bytes_received, sizeof(bitcoin_msg_header) + payload_len);
834 continue;
835 }
836
837 if (strcmp(cmd_name, "ping") == 0)
838 {
839 // Typically 8-byte payload
840 if (payload_len == 8)
841 {
842 ssize_t s = send_pong(node->socket_fd, payload_data);
843 if (s < 0)
844 {
845 log_message(LOG_ERROR, log_filename, __FILE__,
846 "Sending pong: %s\n", strerror(errno));
847 }
848 else
849 {
850 log_message(LOG_INFO, log_filename, __FILE__,
851 "Successfully sent pong");
852 }
853 }
854 else
855 {
856 log_message(LOG_WARN, log_filename, __FILE__,
857 "Ping payload length is not 8 bytes, not sending pong");
858 }
859 }
860 else if (strcmp(cmd_name, "getaddr") == 0)
861 {
862 if (payload_len == 0)
863 {
864 ssize_t s = send_addr(node->socket_fd, node->ip_address);
865 if (s < 0)
866 {
867 log_message(LOG_ERROR, log_filename, __FILE__,
868 "Sending addr: %s\n", strerror(errno));
869 }
870 else
871 {
872 log_message(LOG_INFO, log_filename, __FILE__,
873 "Successfully sent addresses");
874 }
875 }
876 else
877 {
878 log_message(LOG_WARN, log_filename, __FILE__,
879 "Invalid payload length for 'getaddr' command: %zu",
880 payload_len);
881 }
882 }
883 else if (strcmp(cmd_name, "getheaders") == 0)
884 {
885 // Parse the getheaders message
886 size_t offset = sizeof(bitcoin_msg_header);
887 uint32_t version;
888 memcpy(&version, payload_data + offset, 4);
889 offset += 4;
890
891 unsigned char start_hash[32];
892 memcpy(start_hash, payload_data + offset, 32);
893 offset += 32;
894
895 unsigned char stop_hash[32];
896 memcpy(stop_hash, payload_data + offset, 32);
897
898 // Log the received getheaders message
899 log_message(LOG_INFO, log_filename, __FILE__, "Received 'getheaders' message.");
900
901 // Send the headers in response
902 int idx = get_idx(node->ip_address);
903 send_headers(idx, start_hash, stop_hash);
904 }
905 else if (strcmp(cmd_name, "getblocks") == 0)
906 {
907 // Log the received getblocks message
908 log_message(LOG_INFO, log_filename, __FILE__, "Received 'getblocks' message.");
909
910 // Handle the getblocks request
911 size_t payload_len;
912 unsigned char* payload = load_blocks_from_file("blocks.dat", &payload_len);
913 if (!payload)
914 {
915 log_message(LOG_ERROR, log_filename, __FILE__, "Failed to load blocks from file");
916 }
917 else
918 {
919 ssize_t bytes_sent = send(node->socket_fd, payload, payload_len, 0);
920 if (bytes_sent < 0)
921 {
922 log_message(LOG_ERROR, log_filename, __FILE__, "Failed to send blocks: %s", strerror(errno));
923 }
924 else
925 {
926 log_message(LOG_INFO, log_filename, __FILE__, "Sent blocks to node %s", node->ip_address);
927 }
928 free(payload);
929 }
930 }
931 else if (strcmp(cmd_name, "inv") == 0)
932 {
933 // Handle the inv message
934 log_message(LOG_INFO, log_filename, __FILE__, "Received 'inv' message.");
935 int idx = get_idx(node->ip_address);
936 handle_inv_message(idx, payload_data, payload_len);
937 }
938 else if (strcmp(cmd_name, "getdata") == 0)
939 {
940 // Handle the getdata message
941 log_message(LOG_INFO, log_filename, __FILE__, "Received 'getdata' message.");
942 // Load the requested data from file and send it
943 size_t data_len;
944 unsigned char* data = load_blocks_from_file("data.dat", &data_len);
945 if (!data)
946 {
947 log_message(LOG_ERROR, log_filename, __FILE__, "Failed to load data from file");
948 }
949 else
950 {
951 ssize_t bytes_sent = send(node->socket_fd, data, data_len, 0);
952 if (bytes_sent < 0)
953 {
954 log_message(LOG_ERROR, log_filename, __FILE__, "Failed to send data: %s", strerror(errno));
955 }
956 else
957 {
958 log_message(LOG_INFO, log_filename, __FILE__, "Sent data to node %s", node->ip_address);
959 }
960 free(data);
961 }
962 }
963 // Info about compact blocks is saved but handling of compact blocks is not implemented
964 else if (strcmp(cmd_name, "sendcmpct") == 0)
965 {
966 // usually 9 bytes: fannounce(1 byte) + version(8 bytes)
967 if (payload_len == 9)
968 {
969 unsigned char fannounce = payload_data[0];
970 uint64_t cmpctversion;
971 memcpy(&cmpctversion, payload_data + 1, 8);
972 node->compact_blocks = cmpctversion;
973 log_message(LOG_INFO, log_filename, __FILE__,
974 "compactblocks set to: %lu, fannounce: %u",
975 cmpctversion, fannounce);
976 }
977 else
978 {
979 log_message(LOG_WARN, log_filename, __FILE__,
980 "sendcmpct payload length is not 9 bytes, its: %zu",
981 payload_len);
982 }
983 }
984 // Fee rate is saved, but filtering out transactions is not implemented
985 else if (strcmp(cmd_name, "feefilter") == 0)
986 {
987 // 8 bytes: an uint64_t in little-endian indicating min fee rate in sat/kB
988 if (payload_len == 8)
989 {
990 uint64_t fee_rate;
991 memcpy(&fee_rate, payload_data, 8);
992 node->fee_rate = fee_rate;
993 log_message(LOG_INFO, log_filename, __FILE__,
994 "fee rate set to: %lu", fee_rate);
995 }
996 else
997 {
998 log_message(LOG_WARN, log_filename, __FILE__,
999 "feefilter payload length is not 8 bytes, its: %zu",
1000 payload_len);
1001 }
1002 }
1003 }
1004
1005 time_t current_time = time(NULL);
1006 if (difftime(current_time, last_ping_time) >= 5)
1007 {
1008 send_ping(node->socket_fd, node->ip_address);
1009 last_ping_time = current_time;
1010 }
1011 }
1012
1013 close(node->socket_fd); // Close the socket once done
1014 return NULL;
1015}
1016
1018{
1019 if (pthread_create(&node->thread, NULL, peer_communication, (void*)node) != 0)
1020 {
1021 perror("Failed to create thread for peer");
1022 exit(1);
1023 }
1024
1025 if (pthread_detach(node->thread) != 0)
1026 {
1027 perror("Failed to detach thread for peer");
1028 exit(1);
1029 }
1030}
1031
1032int connect_to_peer(const char* ip_addr)
1033{
1034 // Create the socket
1035 int sockfd;
1036 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
1037 {
1038 fprintf(stderr, "[Error] socket creation failed: %s\n", strerror(errno));
1039 return -1;
1040 }
1041
1042 struct timeval timeout;
1043 timeout.tv_sec = 3; // seconds
1044 timeout.tv_usec = 0; // microseconds
1045
1046 // Set timeout for recv
1047 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0)
1048 {
1049 perror("setsockopt failed");
1050 close(sockfd);
1051 exit(EXIT_FAILURE);
1052 }
1053 // Set timeout for connect()
1054 if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) < 0)
1055 {
1056 perror("setsockopt failed");
1057 close(sockfd);
1058 return -1;
1059 }
1060
1061 // Prepare the sockaddr_in
1062 struct sockaddr_in servaddr;
1063 memset(&servaddr, 0, sizeof(servaddr));
1064 servaddr.sin_family = AF_INET;
1065 servaddr.sin_port = htons(BITCOIN_MAINNET_PORT);
1066
1067 if (inet_pton(AF_INET, ip_addr, &servaddr.sin_addr) <= 0)
1068 {
1069 fprintf(stderr, "[Error] inet_pton failed (IP '%s'): %s\n",
1070 ip_addr, strerror(errno));
1071 close(sockfd);
1072 return -1;
1073 }
1074
1075 // Connect
1076 if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
1077 {
1078 fprintf(stderr, "[Error] connect to %s:%d failed: %s\n",
1079 ip_addr, BITCOIN_MAINNET_PORT, strerror(errno));
1080 close(sockfd);
1081 return -1;
1082 }
1083
1084 printf("[+] Connected to peer %s:%d\n", ip_addr, BITCOIN_MAINNET_PORT);
1085
1086 // Build the 'version' payload
1087 unsigned char version_payload[200];
1088 size_t version_payload_len = build_version_payload(
1089 version_payload, sizeof(version_payload));
1090 if (version_payload_len == 0)
1091 {
1092 fprintf(stderr, "[Error] build_version_payload() failed.\n");
1093 close(sockfd);
1094 return -1;
1095 }
1096
1097 // Create the full 'version' message
1098 unsigned char version_msg[256];
1099 size_t version_msg_len = build_message(
1100 version_msg,
1101 sizeof(version_msg),
1102 "version",
1103 version_payload,
1104 version_payload_len
1105 );
1106 if (version_msg_len == 0)
1107 {
1108 fprintf(stderr, "[Error] build_message() failed for 'version'.\n");
1109 close(sockfd);
1110 return -1;
1111 }
1112
1113 // Send the 'version' message
1114 ssize_t bytes_sent = send(sockfd, version_msg, version_msg_len, 0);
1115 if (bytes_sent < 0)
1116 {
1117 fprintf(stderr, "[Error] send() of 'version' failed: %s\n", strerror(errno));
1118 close(sockfd);
1119 return -1;
1120 }
1121 printf("[+] Sent 'version' message (%zd bytes).\n", bytes_sent);
1122
1123 char log_filename[256];
1124 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
1125 ip_addr);
1126 init_logging(log_filename);
1127 // Read loop - up to 10 messages
1128 unsigned char recv_buf[2048];
1129 bool connected = false;
1130 for (int i = 0; i < 4; ++i)
1131 {
1132 printf("[d] Executing %dth receive loop iteration\n", i);
1133 ssize_t n = recv(sockfd, recv_buf, sizeof(recv_buf), 0);
1134 if (n < 0)
1135 {
1136 if (errno == EAGAIN || errno == EWOULDBLOCK)
1137 {
1138 log_message(LOG_WARN, log_filename, __FILE__,
1139 "recv() timed out, continuing...");
1140 continue;
1141 }
1142 fprintf(stderr, "[Error] recv() failed: %s\n", strerror(errno));
1143 break;
1144 }
1145 if (n == 0)
1146 {
1147 // Peer closed the connection
1148 printf("[i] Peer closed the connection.\n");
1149 break;
1150 }
1151
1152 // If we have at least a full header, parse it
1153 if (n < (ssize_t)sizeof(bitcoin_msg_header))
1154 {
1155 printf("[!] Received %zd bytes (less than header size 24).\n", n);
1156 continue;
1157 }
1158
1159 printf("[<] Received %zd bytes.\n", n);
1160
1161 // Cast to a header
1162 bitcoin_msg_header* hdr = (bitcoin_msg_header*)recv_buf;
1163
1164 // Check the magic
1165 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
1166 {
1167 char cmd_name[13];
1168 memset(cmd_name, 0, sizeof(cmd_name));
1169 memcpy(cmd_name, hdr->command, 12);
1170
1171 printf("[<] Received command: '%s'\n", cmd_name);
1172
1173 // Determine the payload length & pointer
1174 size_t payload_len = hdr->length;
1175
1176 if (n < (ssize_t)(sizeof(bitcoin_msg_header) + payload_len))
1177 {
1178 printf("[!] Incomplete message; got %zd bytes, expected %zu.\n",
1179 n, sizeof(bitcoin_msg_header) + payload_len);
1180 continue;
1181 }
1182
1183 // Handle known commands
1184 if (strcmp(cmd_name, "version") == 0)
1185 {
1186 // Send verack once we get their version
1187 ssize_t verack_sent = send_verack(sockfd, ip_addr);
1188 if (verack_sent < 0)
1189 {
1190 fprintf(stderr, "[Error] sending verack: %s\n", strerror(errno));
1191 }
1192 else
1193 {
1194 printf("[+] Sent 'verack' message.\n");
1195 }
1196 connected = true;
1197 }
1198 else if (strcmp(cmd_name, "verack") == 0)
1199 {
1200 connected = true;
1201 break;
1202 }
1203 else
1204 {
1205 // Unhandled command
1206 printf("[!] Unhandled command: '%s' (payload size=%u)\n",
1207 cmd_name, hdr->length);
1208 }
1209 }
1210 else
1211 {
1212 printf("[!] Unexpected magic bytes (0x%08X).\n", hdr->magic);
1213 }
1214 }
1215 if (connected == true)
1216 {
1217 for (int j = 0; j < MAX_NODES; ++j)
1218 {
1219 if (nodes[j].is_connected == 0)
1220 {
1221 guarded_print_line("connected to node: %s | %d.", ip_addr, j);
1222 initialize_node(&nodes[j], ip_addr, 8333, sockfd);
1224 break;
1225 }
1226 }
1227 }
1228 else
1229 {
1230 guarded_print_line("Couldn't connect to node\n");
1231 close(sockfd);
1232 }
1233 return 0;
1234}
1235
1236void disconnect(int node_id)
1237{
1238 if (node_id < 0 || node_id >= MAX_NODES || !nodes[node_id].is_connected)
1239 {
1240 fprintf(stderr, "[Error] Invalid node ID or node not connected.\n");
1241 return;
1242 }
1243
1244 Node* node = &nodes[node_id];
1245 char log_filename[256];
1246 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log",
1247 node->ip_address);
1248
1249 log_message(LOG_INFO, log_filename, __FILE__, "Disconnecting from node %s:%u",
1250 node->ip_address, node->port);
1251
1252 close(node->socket_fd);
1253
1254 node->is_connected = 0;
1255
1256 if (pthread_cancel(node->thread) != 0)
1257 {
1258 perror("Failed to cancel thread for peer");
1259 }
1260
1261 log_message(LOG_INFO, log_filename, __FILE__,
1262 "Successfully disconnected from node %s:%u", node->ip_address,
1263 node->port);
1264}
1265
1266void print_block_header(const unsigned char* header)
1267{
1268 uint32_t version;
1269 unsigned char prev_block[32];
1270 unsigned char merkle_root[32];
1271 uint32_t timestamp;
1272 uint32_t bits;
1273 uint32_t nonce;
1274
1275 memcpy(&version, header, 4);
1276 memcpy(prev_block, header + 4, 32);
1277 memcpy(merkle_root, header + 36, 32);
1278 memcpy(&timestamp, header + 68, 4);
1279 memcpy(&bits, header + 72, 4);
1280 memcpy(&nonce, header + 76, 4);
1281
1282 printf("Version: %u\n", version);
1283 printf("Previous Block Hash: ");
1284 for (int i = 0; i < 32; i++) printf("%02x", prev_block[i]);
1285 printf("\n");
1286 printf("Merkle Root: ");
1287 for (int i = 0; i < 32; i++) printf("%02x", merkle_root[i]);
1288 printf("\n");
1289 printf("Timestamp: %u\n", timestamp);
1290 printf("Bits: %u\n", bits);
1291 printf("Nonce: %u\n", nonce);
1292 printf("\n");
1293}
1294
1295void parse_headers_message(const unsigned char* payload, size_t payload_len)
1296{
1297 size_t offset = 0;
1298 FILE* file = fopen(HEADERS_FILE, "ab");
1299 if (!file)
1300 {
1301 perror("Failed to open headers file");
1302 return;
1303 }
1304
1305 while (offset + 80 <= payload_len)
1306 {
1307 print_block_header(payload + offset);
1308 fwrite(payload + offset, 80, 1, file);
1309 offset += 80;
1310 }
1311
1312 fclose(file);
1313}
1314
1315void load_latest_known_block_hash(unsigned char* block_hash)
1316{
1317 FILE* file = fopen(HEADERS_FILE, "rb");
1318 if (!file)
1319 {
1320 // No known blocks, use genesis block hash
1321 memset(block_hash, 0, 32);
1322 return;
1323 }
1324
1325 fseek(file, -80, SEEK_END);
1326 fread(block_hash, 32, 1, file);
1327 fclose(file);
1328}
1329
1331{
1332 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1333 {
1334 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1335 return;
1336 }
1337
1338 Node* node = &nodes[idx];
1339 char log_filename[256];
1340 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1341
1342 // Define block locator and locator count
1343 unsigned char block_locator[MAX_LOCATOR_COUNT * 32];
1344 int locator_count = 1; // Set to 1 to request headers starting from the latest known block
1345
1346 // Load the latest known block hash
1347 load_latest_known_block_hash(block_locator);
1348
1349 // Build the 'getheaders' message
1350 unsigned char getheaders_msg[sizeof(bitcoin_msg_header) + 4 + 1 + (MAX_LOCATOR_COUNT * 32) + 32];
1351 size_t msg_len = build_getheaders_message(getheaders_msg, sizeof(getheaders_msg), block_locator, locator_count);
1352 if (msg_len == 0)
1353 {
1354 fprintf(stderr, "[Error] Failed to build 'getheaders' message.\n");
1355 return;
1356 }
1357
1358 // Send the 'getheaders' message
1359 ssize_t bytes_sent = send(node->socket_fd, getheaders_msg, msg_len, 0);
1360 if (bytes_sent < 0)
1361 {
1362 log_message(LOG_INFO, log_filename, __FILE__,
1363 "[Error] Failed to send 'getheaders' message: %s", strerror(errno));
1364 return;
1365 }
1366
1367 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getheaders' message.");
1368 node->operation_in_progress = 1;
1369
1370 // Wait for 10 seconds for a response
1371 struct timeval tv;
1372 tv.tv_sec = 10;
1373 tv.tv_usec = 0;
1374 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1375
1376 // Receive the response
1377 unsigned char buffer[4096];
1378 ssize_t bytes_received = recv(node->socket_fd, buffer, sizeof(buffer), 0);
1379 if (bytes_received < 0)
1380 {
1381 log_message(LOG_INFO, log_filename, __FILE__,
1382 "[Error] Failed to receive response: %s", strerror(errno));
1383 node->operation_in_progress = 0;
1384 return;
1385 }
1386
1387 log_message(LOG_INFO, log_filename, __FILE__, "Received response to 'getheaders' message.");
1388 node->operation_in_progress = 0;
1389
1390 // Process the response and print to CLI
1391 guarded_print("Received response to 'getheaders' message:\n");
1392 parse_headers_message(buffer, bytes_received);
1393}
1394
1395void send_headers(int idx, const unsigned char* start_hash, const unsigned char* stop_hash)
1396{
1397 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1398 {
1399 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1400 return;
1401 }
1402
1403 Node* node = &nodes[idx];
1404 char log_filename[256];
1405 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1406
1407 // Open the headers file
1408 FILE* file = fopen(HEADERS_FILE, "rb");
1409 if (!file)
1410 {
1411 perror("Failed to open headers file");
1412 return;
1413 }
1414
1415 // Find the starting block header
1416 unsigned char buffer[81];
1417 size_t headers_count = 0;
1418 int found_start = 0;
1419 while (fread(buffer, 80, 1, file) == 1)
1420 {
1421 if (memcmp(buffer, start_hash, 32) == 0)
1422 {
1423 found_start = 1;
1424 break;
1425 }
1426 }
1427
1428 if (!found_start)
1429 {
1430 fclose(file);
1431 fprintf(stderr, "[Error] Start hash not found in headers file.\n");
1432 return;
1433 }
1434
1435 // Build the 'headers' message
1436 unsigned char headers_msg[sizeof(bitcoin_msg_header) + 1 + (MAX_HEADERS_COUNT * 81)];
1437 size_t offset = sizeof(bitcoin_msg_header);
1438 headers_msg[offset++] = 0; // Placeholder for count
1439
1440 while (headers_count < MAX_HEADERS_COUNT && fread(buffer, 80, 1, file) == 1)
1441 {
1442 memcpy(headers_msg + offset, buffer, 80);
1443 offset += 80;
1444 headers_msg[offset++] = 0; // Transaction count (var_int, 0 for headers only)
1445 headers_count++;
1446
1447 if (memcmp(buffer, stop_hash, 32) == 0)
1448 {
1449 break;
1450 }
1451 }
1452
1453 fclose(file);
1454
1455 // Set the count
1456 headers_msg[sizeof(bitcoin_msg_header)] = headers_count;
1457
1458 // Build the message header
1459 bitcoin_msg_header* header = (bitcoin_msg_header*)headers_msg;
1461 strncpy(header->command, "headers", 12);
1462 header->length = htole32(offset - sizeof(bitcoin_msg_header));
1463 compute_checksum(headers_msg + sizeof(bitcoin_msg_header), offset - sizeof(bitcoin_msg_header), header->checksum);
1464
1465 // Send the 'headers' message
1466 ssize_t bytes_sent = send(node->socket_fd, headers_msg, offset, 0);
1467 if (bytes_sent < 0)
1468 {
1469 log_message(LOG_INFO, log_filename, __FILE__,
1470 "[Error] Failed to send 'headers' message: %s", strerror(errno));
1471 return;
1472 }
1473
1474 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'headers' message.");
1475}
1476
1477void save_blocks_to_file(const unsigned char* payload, size_t payload_len, const char* filename)
1478{
1479 FILE* file = fopen(filename, "wb");
1480 if (!file)
1481 {
1482 perror("Failed to open file for writing");
1483 return;
1484 }
1485
1486 fwrite(payload, 1, payload_len, file);
1487 fclose(file);
1488 guarded_print("Blocks saved to file: %s\n", filename);
1489}
1490
1491unsigned char* load_blocks_from_file(const char* filename, size_t* payload_len)
1492{
1493 FILE* file = fopen(filename, "rb");
1494 if (!file)
1495 {
1496 perror("Failed to open file for reading");
1497 return NULL;
1498 }
1499
1500 fseek(file, 0, SEEK_END);
1501 *payload_len = ftell(file);
1502 fseek(file, 0, SEEK_SET);
1503
1504 unsigned char* payload = (unsigned char*)malloc(*payload_len);
1505 if (!payload)
1506 {
1507 perror("Failed to allocate memory");
1508 fclose(file);
1509 return NULL;
1510 }
1511
1512 fread(payload, 1, *payload_len, file);
1513 fclose(file);
1514 guarded_print("Blocks loaded from file: %s\n", filename);
1515 return payload;
1516}
1517
1519{
1520 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1521 {
1522 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1523 return;
1524 }
1525
1526 Node* node = &nodes[idx];
1527 char log_filename[256];
1528 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1529
1530 // Define block locator and locator count
1531 unsigned char block_locator[MAX_LOCATOR_COUNT * 32];
1532 int locator_count = 1; // Set to 1 to request blocks starting from the latest known block
1533
1534 // Load the latest known block hash
1535 load_latest_known_block_hash(block_locator);
1536
1537 // Build the 'getblocks' message
1538 unsigned char getblocks_msg[sizeof(bitcoin_msg_header) + 4 + 1 + (MAX_LOCATOR_COUNT * 32) + 32];
1539 size_t msg_len = build_getblocks_message(getblocks_msg, sizeof(getblocks_msg), block_locator, locator_count);
1540 if (msg_len == 0)
1541 {
1542 fprintf(stderr, "[Error] Failed to build 'getblocks' message.\n");
1543 return;
1544 }
1545
1546 // Send the 'getblocks' message
1547 ssize_t bytes_sent = send(node->socket_fd, getblocks_msg, msg_len, 0);
1548 if (bytes_sent < 0)
1549 {
1550 log_message(LOG_INFO, log_filename, __FILE__,
1551 "[Error] Failed to send 'getblocks' message: %s", strerror(errno));
1552 return;
1553 }
1554
1555 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getblocks' message.");
1556 node->operation_in_progress = 1;
1557
1558 // Wait for 10 seconds for a response
1559 struct timeval tv;
1560 tv.tv_sec = 10;
1561 tv.tv_usec = 0;
1562 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1563
1564 // Increase buffer size to handle larger responses
1565 unsigned char buffer[32768];
1566 size_t total_bytes_received = 0;
1567 ssize_t bytes_received;
1568
1569 // Receive the message in parts
1570 while ((bytes_received = recv(node->socket_fd, buffer + total_bytes_received, sizeof(buffer) - total_bytes_received - 1, 0)) > 0)
1571 {
1572 total_bytes_received += bytes_received;
1573 }
1574
1575 if (bytes_received < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1576 {
1577 log_message(LOG_INFO, log_filename, __FILE__,
1578 "[Error] Failed to receive response: %s", strerror(errno));
1579 node->operation_in_progress = 0;
1580 return;
1581 }
1582
1583 log_message(LOG_INFO, log_filename, __FILE__, "Received response to 'getblocks' message.");
1584 node->operation_in_progress = 0;
1585
1586 // Process the response and print to CLI
1587 guarded_print("Received response to 'getblocks' message:\n");
1588 parse_inv_message(buffer, total_bytes_received);
1589
1590 // Save the blocks to a file
1591 save_blocks_to_file(buffer, total_bytes_received, "blocks.dat");
1592}
1593
1594size_t build_getblocks_message(unsigned char* buffer, size_t buffer_size, const unsigned char* block_locator, size_t locator_count)
1595{
1596 if (buffer_size < sizeof(bitcoin_msg_header) + 37)
1597 return 0;
1598
1599 unsigned char payload[4 + 1 + (locator_count * 32) + 32];
1600
1601 // Set protocol version (4 bytes)
1602 uint32_t version = htonl(70015);
1603 memcpy(payload, &version, 4);
1604
1605 // Set block locator count (var_int encoding)
1606 size_t offset = 4;
1607 offset += write_var_int(payload + offset, locator_count);
1608
1609 // Copy block locator hashes
1610 memcpy(payload + offset, block_locator, locator_count * 32);
1611 offset += locator_count * 32;
1612
1613 // Set hash_stop (32 bytes of zeros for max 500 blocks)
1614 memset(payload + offset, 0, 32);
1615 offset += 32;
1616
1617 // Ensure buffer is large enough
1618 if (offset > buffer_size)
1619 return 0;
1620
1621 // Build final message
1622 return build_message(buffer, buffer_size, "getblocks", payload, offset);
1623}
1624
1625void parse_inv_message(const unsigned char* payload, size_t payload_len)
1626{
1627 size_t offset = 0;
1628 uint64_t count = read_var_int(payload + offset, &offset);
1629
1630 guarded_print("Inventory count: %llu\n", count);
1631
1632 for (uint64_t i = 0; i < count; i++)
1633 {
1634 if (offset + 36 > payload_len)
1635 {
1636 guarded_print("Insufficient payload length for inventory entry\n");
1637 return;
1638 }
1639
1640 uint32_t type;
1641 memcpy(&type, payload + offset, 4);
1642 offset += 4;
1643
1644 unsigned char hash[32];
1645 memcpy(hash, payload + offset, 32);
1646 offset += 32;
1647
1648 guarded_print("Inventory item %llu: Type: %u, Hash: ", i + 1, type);
1649 for (int j = 0; j < 32; j++)
1650 {
1651 guarded_print("%02x", hash[j]);
1652 }
1653 guarded_print("\n");
1654 }
1655}
1656
1657void handle_inv_message(int idx, const unsigned char* payload, size_t payload_len)
1658{
1659 size_t offset = 0;
1660 uint64_t count = read_var_int(payload + offset, &offset);
1661
1662 if (count == 0 || count > 50000)
1663 {
1664 log_message(LOG_WARN, BITLAB_LOG, __FILE__,
1665 "Invalid inventory count in inv message: %llu", count);
1666 return;
1667 }
1668
1669 unsigned char hashes[count * 32];
1670 size_t hash_count = 0;
1671
1672 for (uint64_t i = 0; i < count; i++)
1673 {
1674 if (offset + 36 > payload_len)
1675 {
1676 log_message(LOG_WARN, BITLAB_LOG, __FILE__,
1677 "Insufficient payload length for inventory entry");
1678 return;
1679 }
1680
1681 uint32_t type;
1682 memcpy(&type, payload + offset, 4);
1683 offset += 4;
1684
1685 if (type == 2) // Type 2 for block (1 for transaction)
1686 {
1687 memcpy(hashes + (hash_count * 32), payload + offset, 32);
1688 hash_count++;
1689 }
1690 offset += 32;
1691 }
1692
1693 if (hash_count > 0)
1694 {
1695 send_getdata_and_wait(idx, hashes, hash_count);
1696 }
1697}
1698
1699size_t build_getdata_message(unsigned char* buffer, size_t buffer_size, const unsigned char* hashes, size_t hash_count)
1700{
1701 if (buffer_size < sizeof(bitcoin_msg_header) + 1 + (hash_count * 36))
1702 return 0;
1703
1704 unsigned char payload[1 + (hash_count * 36)];
1705
1706 // Set inventory count (var_int encoding)
1707 size_t offset = 0;
1708 offset += write_var_int(payload + offset, hash_count);
1709
1710 // Copy inventory vectors (type + hash)
1711 for (size_t i = 0; i < hash_count; i++)
1712 {
1713 uint32_t type = htonl(2); // Assuming type 2 for block (1 for transaction)
1714 memcpy(payload + offset, &type, 4);
1715 offset += 4;
1716 memcpy(payload + offset, hashes + (i * 32), 32);
1717 offset += 32;
1718 }
1719
1720 // Ensure buffer is large enough
1721 if (offset > buffer_size)
1722 return 0;
1723
1724 // Build final message
1725 return build_message(buffer, buffer_size, "getdata", payload, offset);
1726}
1727
1728void send_getdata_and_wait(int idx, const unsigned char* hashes, size_t hash_count)
1729{
1730 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1731 {
1732 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1733 return;
1734 }
1735
1736 if (hash_count == 0 || hash_count > 50000)
1737 {
1738 fprintf(stderr, "[Error] Invalid hash count. Must be between 1 and 50000.\n");
1739 return;
1740 }
1741
1742 Node* node = &nodes[idx];
1743 char log_filename[256];
1744 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1745
1746 // Build the 'getdata' message
1747 unsigned char getdata_msg[sizeof(bitcoin_msg_header) + 1 + (hash_count * 36)];
1748 size_t msg_len = build_getdata_message(getdata_msg, sizeof(getdata_msg), hashes, hash_count);
1749 if (msg_len == 0)
1750 {
1751 fprintf(stderr, "[Error] Failed to build 'getdata' message.\n");
1752 return;
1753 }
1754
1755 // Send the 'getdata' message
1756 ssize_t bytes_sent = send(node->socket_fd, getdata_msg, msg_len, 0);
1757 if (bytes_sent < 0)
1758 {
1759 log_message(LOG_INFO, log_filename, __FILE__,
1760 "[Error] Failed to send 'getdata' message: %s", strerror(errno));
1761 return;
1762 }
1763
1764 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'getdata' message.");
1765 node->operation_in_progress = 1;
1766
1767 // Wait for 20 seconds for a response (increased timeout)
1768 struct timeval tv;
1769 tv.tv_sec = 20;
1770 tv.tv_usec = 0;
1771 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1772
1773 // Receive the response
1774 unsigned char buffer[32768];
1775 ssize_t bytes_received;
1776
1777 while ((bytes_received = recv(node->socket_fd, buffer, sizeof(buffer), 0)) > 0)
1778 {
1779 bitcoin_msg_header* hdr = (bitcoin_msg_header*)buffer;
1780 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
1781 {
1782 char cmd_name[13];
1783 memset(cmd_name, 0, sizeof(cmd_name));
1784 memcpy(cmd_name, hdr->command, 12);
1785
1786 if (strcmp(cmd_name, "block") == 0)
1787 {
1788 log_message(LOG_INFO, log_filename, __FILE__, "Received 'block' message.");
1789 decode_transactions(buffer + sizeof(bitcoin_msg_header), hdr->length);
1790 }
1791 }
1792 }
1793
1794 if (bytes_received < 0 && errno != EAGAIN && errno != EWOULDBLOCK)
1795 {
1796 log_message(LOG_INFO, log_filename, __FILE__,
1797 "[Error] Failed to receive block message: %s", strerror(errno));
1798 }
1799
1800 node->operation_in_progress = 0;
1801}
1802
1814size_t build_inv_message(unsigned char* buffer, size_t buffer_size, const unsigned char* inv_data, size_t inv_count)
1815{
1816 size_t var_int_size = write_var_int(NULL, inv_count); // Get the size of the var_int encoding
1817 size_t payload_size = var_int_size + (inv_count * 36); // var_int size + 36 bytes per inventory vector
1818
1819 printf("inv_count: %zu, payload_size: %zu, buffer_size: %zu\n", inv_count, payload_size, buffer_size);
1820
1821 if (buffer_size < sizeof(bitcoin_msg_header) + payload_size)
1822 {
1823 printf("Buffer size is too small: buffer_size=%zu, required=%zu\n", buffer_size, sizeof(bitcoin_msg_header) + payload_size);
1824 return 0;
1825 }
1826
1827 unsigned char* payload = (unsigned char*)malloc(payload_size);
1828 if (!payload)
1829 {
1830 printf("Failed to allocate memory for payload\n");
1831 return 0;
1832 }
1833
1834 // Set inventory count (var_int encoding)
1835 size_t offset = 0;
1836 offset += write_var_int(payload + offset, inv_count);
1837 log_message(LOG_DEBUG, BITLAB_LOG, __FILE__, "After write_var_int: offset=%zu", offset);
1838
1839 // Copy inventory vectors (type + hash)
1840 for (size_t i = 0; i < inv_count; i++)
1841 {
1842 memcpy(payload + offset, inv_data + (i * 36), 36);
1843 offset += 36;
1844 }
1845 printf("After copying inventory vectors: offset=%zu\n", offset);
1846
1847 // Build final message
1848 size_t message_size = build_message(buffer, buffer_size, "inv", payload, payload_size);
1849 printf("Built message size: %zu\n", message_size);
1850
1851 free(payload);
1852 return message_size;
1853}
1854
1866void send_inv_and_wait(int idx, const unsigned char* inv_data, size_t inv_count)
1867{
1868 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
1869 {
1870 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
1871 return;
1872 }
1873
1874 if (inv_count == 0 || inv_count > 50000)
1875 {
1876 fprintf(stderr, "[Error] Invalid inventory count. Must be between 1 and 50000.\n");
1877 return;
1878 }
1879
1880 Node* node = &nodes[idx];
1881 char log_filename[256];
1882 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
1883
1884 size_t var_int_size = write_var_int(NULL, inv_count); // Get the size of the var_int encoding
1885 size_t payload_size = var_int_size + (inv_count * 36); // var_int size + 36 bytes per inventory vector
1886 size_t inv_msg_size = sizeof(bitcoin_msg_header) + payload_size;
1887
1888 printf("inv_count: %zu, inv_msg_size: %zu\n", inv_count, inv_msg_size);
1889
1890 unsigned char* inv_msg = (unsigned char*)malloc(inv_msg_size);
1891 if (!inv_msg)
1892 {
1893 fprintf(stderr, "[Error] Failed to allocate memory for 'inv' message.\n");
1894 return;
1895 }
1896
1897 size_t msg_len = build_inv_message(inv_msg, inv_msg_size, inv_data, inv_count);
1898 printf("msg_len: %zu\n", msg_len);
1899 if (msg_len == 0)
1900 {
1901 fprintf(stderr, "[Error] Failed to build 'inv' message.\n");
1902 free(inv_msg);
1903 return;
1904 }
1905
1906 // Send the 'inv' message
1907 ssize_t bytes_sent = send(node->socket_fd, inv_msg, msg_len, 0);
1908 if (bytes_sent < 0)
1909 {
1910 log_message(LOG_INFO, log_filename, __FILE__,
1911 "[Error] Failed to send 'inv' message: %s", strerror(errno));
1912 free(inv_msg);
1913 return;
1914 }
1915
1916 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'inv' message.");
1917 printf("Sent 'inv' message.\n");
1918 node->operation_in_progress = 1;
1919
1920 // Wait for 10 seconds for a response
1921 struct timeval tv;
1922 tv.tv_sec = 10;
1923 tv.tv_usec = 0;
1924 setsockopt(node->socket_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
1925
1926 // Receive the response
1927 unsigned char buffer[32768];
1928 ssize_t bytes_received = recv(node->socket_fd, buffer, sizeof(buffer), 0);
1929 if (bytes_received < 0)
1930 {
1931 log_message(LOG_INFO, log_filename, __FILE__,
1932 "[Error] Failed to receive response: %s", strerror(errno));
1933 node->operation_in_progress = 0;
1934 free(inv_msg);
1935 return;
1936 }
1937
1938 log_message(LOG_INFO, log_filename, __FILE__, "Received response to 'inv' message.");
1939 printf("Received response to 'inv' message.\n");
1940 node->operation_in_progress = 0;
1941
1942 // Process the response
1943 if (bytes_received >= (ssize_t)sizeof(bitcoin_msg_header))
1944 {
1945 bitcoin_msg_header* hdr = (bitcoin_msg_header*)buffer;
1946 if (hdr->magic == BITCOIN_MAINNET_MAGIC)
1947 {
1948 char cmd_name[13];
1949 memset(cmd_name, 0, sizeof(cmd_name));
1950 memcpy(cmd_name, hdr->command, 12);
1951
1952 printf("Received command: '%s'\n", cmd_name);
1953
1954 if (strcmp(cmd_name, "inv") == 0)
1955 {
1956 printf("Received 'inv' response:\n");
1957 handle_inv_message(idx, buffer + sizeof(bitcoin_msg_header), bytes_received - sizeof(bitcoin_msg_header));
1958 }
1959 else
1960 {
1961 printf("Unhandled command: '%s'\n", cmd_name);
1962 }
1963 }
1964 else
1965 {
1966 printf("Unexpected magic bytes (0x%08X).\n", hdr->magic);
1967 }
1968 }
1969 else
1970 {
1971 printf("Received incomplete message.\n");
1972 }
1973
1974 free(inv_msg);
1975}
1976
1977void decode_transactions(const unsigned char* block_data, size_t block_len)
1978{
1979 (void)block_len; // Mark block_len as unused to avoid the warning
1980
1981 size_t offset = 0;
1982
1983 // Skip the block header (80 bytes)
1984 offset += 80;
1985
1986 // Read the number of transactions (var_int)
1987 uint64_t tx_count = read_var_int(block_data + offset, &offset);
1988
1989 printf("Number of transactions: %lu\n", tx_count);
1990
1991 for (uint64_t i = 0; i < tx_count; i++)
1992 {
1993 // Decode each transaction (simplified for demonstration)
1994 printf("Transaction %lu:\n", i + 1);
1995
1996 // Read transaction version (4 bytes)
1997 uint32_t tx_version;
1998 memcpy(&tx_version, block_data + offset, 4);
1999 offset += 4;
2000 printf(" Version: %u\n", tx_version);
2001
2002 // Read the number of inputs (var_int)
2003 uint64_t input_count = read_var_int(block_data + offset, &offset);
2004 printf(" Number of inputs: %lu\n", input_count);
2005
2006 // Read each input (simplified)
2007 for (uint64_t j = 0; j < input_count; j++)
2008 {
2009 // Skip previous output (32 bytes hash + 4 bytes index)
2010 offset += 36;
2011
2012 // Read script length (var_int)
2013 uint64_t script_len = read_var_int(block_data + offset, &offset);
2014
2015 // Skip script and sequence (script_len + 4 bytes)
2016 offset += script_len + 4;
2017 }
2018
2019 // Read the number of outputs (var_int)
2020 uint64_t output_count = read_var_int(block_data + offset, &offset);
2021 printf(" Number of outputs: %lu\n", output_count);
2022
2023 // Read each output (simplified)
2024 for (uint64_t j = 0; j < output_count; j++)
2025 {
2026 // Read value (8 bytes)
2027 uint64_t value;
2028 memcpy(&value, block_data + offset, 8);
2029 offset += 8;
2030 printf(" Value: %lu\n", value);
2031
2032 // Read script length (var_int)
2033 uint64_t script_len = read_var_int(block_data + offset, &offset);
2034
2035 // Skip script (script_len bytes)
2036 offset += script_len;
2037 }
2038
2039 // Read lock time (4 bytes)
2040 uint32_t lock_time;
2041 memcpy(&lock_time, block_data + offset, 4);
2042 offset += 4;
2043 printf(" Lock time: %u\n", lock_time);
2044 }
2045}
2046
2047void send_tx(int idx, const unsigned char* tx_data, size_t tx_size)
2048{
2049 if (idx < 0 || idx >= MAX_NODES || !nodes[idx].is_connected)
2050 {
2051 fprintf(stderr, "[Error] Invalid node index or node not connected.\n");
2052 return;
2053 }
2054
2055 Node* node = &nodes[idx];
2056 char log_filename[256];
2057 snprintf(log_filename, sizeof(log_filename), "peer_connection_%s.log", node->ip_address);
2058
2059 if (!tx_data || tx_size == 0)
2060 {
2061 fprintf(stderr, "[Error] Invalid transaction data.\n");
2062 return;
2063 }
2064
2065 // Build the 'tx' message with the appropriate header
2066 unsigned char tx_msg[sizeof(bitcoin_msg_header) + tx_size];
2067
2068 // Build the message header
2069 bitcoin_msg_header* header = (bitcoin_msg_header*)tx_msg;
2071 strncpy(header->command, "tx", 12);
2072 header->length = htole32(tx_size);
2073 compute_checksum(tx_data, tx_size, header->checksum);
2074
2075 // Copy the transaction data
2076 memcpy(tx_msg + sizeof(bitcoin_msg_header), tx_data, tx_size);
2077
2078 // Send the 'tx' message
2079 ssize_t bytes_sent = send(node->socket_fd, tx_msg, sizeof(bitcoin_msg_header) + tx_size, 0);
2080 if (bytes_sent < 0)
2081 {
2082 log_message(LOG_INFO, log_filename, __FILE__,
2083 "[Error] Failed to send 'tx' message: %s", strerror(errno));
2084 return;
2085 }
2086
2087 log_message(LOG_INFO, log_filename, __FILE__, "Sent 'tx' message (%zu bytes).", tx_size);
2088}
int is_in_private_network(const char *ip_addr)
Check if the IP address is in the private prefix (e.g.
Definition ip.c:98
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.
Definition log.c:89
void init_logging(const char *filename)
Initialize logging used to initialize the logging system, open and preserve the log file.
Definition log.c:34
#define BITLAB_LOG
Definition log.h:11
@ LOG_ERROR
Definition log.h:32
@ LOG_INFO
Definition log.h:30
@ LOG_DEBUG
Definition log.h:29
@ LOG_WARN
Definition log.h:31
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.
Node nodes[MAX_NODES]
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 htole32(x)
#define MAX_NODES
#define MAX_LOCATOR_COUNT
#define BITCOIN_MAINNET_MAGIC
#define HEADERS_FILE
Peer * get_peer_queue(int *count)
Get the peer queue.
Definition peer_queue.c:118
void add_peer_to_queue(const char *ip, int port)
Add a peer to the queue.
Definition peer_queue.c:15
The structure to store information about a connected peer.
char ip_address[64]
uint16_t port
pthread_t thread
uint64_t fee_rate
int socket_fd
uint64_t compact_blocks
int is_connected
int operation_in_progress
The peer structure used to store the peer information obtained by peer discovery process.
Definition peer_queue.h:16
unsigned char checksum[4]
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.
Definition utils.c:116
void guarded_print_line(const char *format,...)
Guarded print line function.
Definition utils.c:65
void guarded_print(const char *format,...)
Guarded print function.
Definition utils.c:55