Przeglądaj źródła

ajout spy3

master
MEUNIER Thibaud 1 rok temu
rodzic
commit
11296dfae5
3 zmienionych plików z 856 dodań i 17 usunięć
  1. +2
    -1
      README.md
  2. +59
    -16
      src/spy2.c
  3. +795
    -0
      src/spy3.c

+ 2
- 1
README.md Wyświetl plik

@ -1,3 +1,4 @@
# btcspy
a tool to observe btc blokcchain
a tool to observe btc blokcchain

+ 59
- 16
src/spy2.c Wyświetl plik

@ -20,6 +20,7 @@
*/
char* simple_db_path = "data/simpledb";
FILE* blockchain_fd = NULL;
FILE* emptyblock_fd = NULL;
/*
* Les outils
@ -234,6 +235,7 @@ static void cb_handshake_done(struct btc_node_ *node)
#define MARGE_TAMPON 20
char buffer[MARGE_TAMPON][65];
uint32_t read_height[MARGE_TAMPON];
uint32_t read_nb_tx[MARGE_TAMPON];
fpos_t fpos[MARGE_TAMPON];
(void) fseek(blockchain_fd, 0L, SEEK_SET);
for(uint i = 0; i < MARGE_TAMPON; i++)
@ -245,13 +247,14 @@ static void cb_handshake_done(struct btc_node_ *node)
request_headers_or_blocks_hash_init = false;
while(fscanf(blockchain_fd, "%s %d\n", buffer[0], read_height))
while(fscanf(blockchain_fd, "%s %d %d\n", buffer[0], read_height, read_nb_tx))
{
/* Décaler le tampon d'un cran vers le bas */
for(uint i = (MARGE_TAMPON-1); i > 0 ; i--)
{
strcpy(buffer[i], buffer[i-1]);
read_height[i] = read_height[i-1];
read_nb_tx[i] = read_nb_tx[i-1];
memcpy(fpos+i, fpos+(i-1), sizeof(fpos_t));
}
@ -260,7 +263,7 @@ static void cb_handshake_done(struct btc_node_ *node)
if (read_height[0] > MARGE_TAMPON)
{
/*
* On se sert du haut d ela pile comme point de départ
* On se sert du haut de la pile comme point de départ
*/
int outlen;
node->nodegroup->log_write_cb("STATUS : Setting requested hash with %s\n", buffer[19]);
@ -366,7 +369,7 @@ static void cb_post_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct con
uint64_t reward = 5000000000;
/*
* La synchro des ent^tes n'est pas terminée
* La synchro des entêtes n'est pas terminée
* Dans ce cas on ne traite pas le bloc ...
*/
if (node->bestknownheight > cb_handshake_done_bestknownheight) return;
@ -489,6 +492,17 @@ static void cb_post_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct con
}
}
if (nb_tx == 1)
{
if (emptyblock_fd != NULL)
{
(void) fseek(emptyblock_fd, 0L, SEEK_END);
fprintf(emptyblock_fd, "%s %d\n", hash_hex_str, block_height);
fflush(emptyblock_fd);
}
}
sprintf(block_filename,"%s/blocks/%u_%s", simple_db_path, block_height, hash_hex_str);
if (file_exist(block_filename)) return;
@ -613,7 +627,7 @@ static void cb_post_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct con
if (!flag_local)
{
(void) fseek(blockchain_fd, 0L, SEEK_END);
fprintf(blockchain_fd, "%s %d\n", hash_hex_str,cb_handshake_done_bestknownheight );
fprintf(blockchain_fd, "%s %d\n", hash_hex_str,cb_handshake_done_bestknownheight);
}
}
} else {
@ -641,24 +655,30 @@ static void cb_post_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct con
}
/*
* Gestion du fichier de chaine de blocks
* Init d'un eliste de blocs
*/
int init_blockchain_file()
FILE* init_blocklist_file(char* filename)
{
const char* blockchain_filename = "blockchain.txt";
FILE* fd = NULL;
char* blockchain_full_filename = NULL;
char buffer[65];
uint32_t block_height;
blockchain_full_filename = calloc(strlen(simple_db_path)+strlen(blockchain_filename)+2, sizeof(char));
if (blockchain_full_filename == NULL) return 1;
blockchain_full_filename = calloc(strlen(simple_db_path)+strlen(filename)+2, sizeof(char));
if (blockchain_full_filename == NULL) return NULL;
/*
*
* init de la liste des blocs vides
*
*/
sprintf(blockchain_full_filename,"%s/%s", simple_db_path, blockchain_filename);
sprintf(blockchain_full_filename,"%s/%s", simple_db_path, filename);
if (!file_exist(blockchain_full_filename))
{
blockchain_fd = fopen(blockchain_full_filename,"w");
if (blockchain_fd != NULL)
fd = fopen(blockchain_full_filename,"w");
if (fd != NULL)
{
int outlen;
@ -668,9 +688,9 @@ int init_blockchain_file()
sprintf(buffer, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
block_height = 0;
fprintf(blockchain_fd, "%s %d\n", buffer, block_height);
fclose(blockchain_fd);
blockchain_fd = NULL;
fprintf(fd, "%s %d\n", buffer, block_height);
fclose(fd);
fd = NULL;
utils_reverse_hex(buffer, 64);
utils_hex_to_bin(buffer, request_headers_or_blocks_hash, 64, &outlen);
@ -680,7 +700,30 @@ int init_blockchain_file()
}
}
blockchain_fd = fopen(blockchain_full_filename,"r+");
fd = fopen(blockchain_full_filename,"r+");
return fd;
}
/*
* Gestion du fichier de chaine de blocks
*/
int init_blockchain_file()
{
const char* blockchain_filename = "blockchain.txt";
const char* emptyblock_filename = "emptyblocks.txt";
char* blockchain_full_filename = NULL;
char buffer[65];
uint32_t block_height;
/*
* Init de la liste des blocks vides
*/
emptyblock_fd = init_blocklist_file("emptyblocks.txt");
/*
* Init de la liste complete des blocks
*/
blockchain_fd = init_blocklist_file("blockchain.txt");
if (blockchain_fd != NULL)
{
while(fscanf(blockchain_fd, "%s %d\n", buffer, &block_height))

+ 795
- 0
src/spy3.c Wyświetl plik

@ -0,0 +1,795 @@
#include <sys/resource.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <btc/block.h>
#include <btc/net.h>
#include <btc/utils.h>
#include <btc/serialize.h>
#include <btc/memory.h>
#include <btc/tx.h>
/*
* Les variables globales
*/
char* simple_db_path = "data/simpledb";
FILE* blockchain_fd = NULL;
FILE* emptyblock_fd = NULL;
/*
* Les outils
*/
static btc_bool file_exist(const char *filename)
{
struct stat buffer;
return (stat(filename, &buffer) == 0);
}
/*
* Les fonctions spécfiques
*/
void request_header_or_block_from_hashbin(btc_node *node, uint256* hash, btc_bool blocks)
{
if (node == NULL) return;
if (hash == NULL) return;
// request next headers
vector* blocklocators = vector_new(1, NULL);
cstring* getheader_msg = cstr_new_sz(256);
cstring* p2p_msg = NULL;
vector_add(blocklocators, (void *)hash);
btc_p2p_msg_getheaders(blocklocators, NULL, getheader_msg);
/* create p2p message */
p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, (blocks ? BTC_MSG_GETBLOCKS : BTC_MSG_GETHEADERS), getheader_msg->str, getheader_msg->len);
/* send message */
btc_node_send(node, p2p_msg);
node->state |= ( blocks ? NODE_BLOCKSYNC : NODE_HEADERSYNC);
/* remember last headers request time */
if (blocks) {
node->time_last_request = time(NULL);
}
/* cleanup */
vector_free(blocklocators, true);
cstr_free(p2p_msg, true);
cstr_free(getheader_msg, true);
}
void request_header_or_block_from_hashhex(btc_node *node, const char* hex, btc_bool blocks)
{
if (node == NULL) return;
if (hex == NULL) return;
uint256 *hash = btc_calloc(1, sizeof(uint256));
if (hash == NULL) return;
utils_uint256_sethex((char *)hex, (uint8_t *)hash);
request_header_or_block_from_hashbin(node,hash,blocks);
}
uint256 request_headers_or_blocks_hash;
btc_bool request_headers_or_blocks_hash_init = false;
void request_headers_or_blocks(btc_node *node, btc_bool blocks)
{
/* Sans initialisation, on repart du Genesis Block */
if (!request_headers_or_blocks_hash_init)
{
node->nodegroup->log_write_cb("STATUS : Setting requested hash with genesis block\n");
memcpy(&request_headers_or_blocks_hash, node->nodegroup->chainparams->genesisblockhash, sizeof(uint256));
request_headers_or_blocks_hash_init = true;
}
// On lance la recherche la synchro
if (request_headers_or_blocks_hash_init)
request_header_or_block_from_hashbin(node, &request_headers_or_blocks_hash, blocks);
}
static void find_and_add_nodes(btc_node_group* group)
{
const btc_dns_seed seed = btc_chainparams_main.dnsseeds[0];
vector* ips;
/* collect and add some btc nodes to the group */
ips = vector_new(group->desired_amount_connected_nodes + 5, free);
btc_get_peers_from_dns(seed.domain, ips, btc_chainparams_main.default_port, AF_INET);
for (unsigned int i = 0; i<ips->len; i++)
{
/* create a node */
btc_node *node = btc_node_new();
char *ip = (char *)vector_idx(ips, i);
btc_node_set_ipport(node, ip);
btc_node_group_add_node(group, node);
}
vector_free(ips, true);
/* connect to the next node */
btc_node_group_connect_next_nodes(group);
}
static void check_connected_nodes(btc_node_group* group)
{
int nb_connected = btc_node_group_amount_of_connected_nodes(group, NODE_CONNECTED);
if (nb_connected < group->desired_amount_connected_nodes)
{
group->log_write_cb("STATUS : new connection needed (%d node connected)\n", nb_connected);
find_and_add_nodes(group);
}
}
/*
* Les callbacks
*/
static int cb_default_write_log(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
return 1;
}
FILE* cb_file_write_log_fp = NULL;
btc_bool cb_file_write_log_flag = false;
char* cb_file_write_log_filter = "";
static int cb_file_write_log(const char *format, ...)
{
if (cb_file_write_log_flag)
{
// Appliquer le filtre
unsigned int limit = strlen(cb_file_write_log_filter);
for(unsigned int i=0; i < limit; i++)
if (format[i] != cb_file_write_log_filter[i])
return 1;
// Ouvrir le flix si besoin
if (cb_file_write_log_fp == NULL)
cb_file_write_log_fp = fopen("log.txt","a+");
// Impossible d'ouvrir le fichier de log
if (cb_file_write_log_fp == NULL) return 0;
va_list args;
va_start(args, format);
vfprintf(cb_file_write_log_fp, format, args);
va_end(args);
fflush(cb_file_write_log_fp);
} else {
if (cb_file_write_log_fp != NULL)
{
// Fermer le flux
fclose(cb_file_write_log_fp);
cb_file_write_log_fp = NULL;
}
}
return 1;
}
static btc_bool cb_timer(btc_node *node, uint64_t *now)
{
check_connected_nodes(node->nodegroup);
/* return true = run internal timer logic (ping, disconnect-timeout, etc.) */
return true;
}
static btc_bool cb_parse_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf)
{
(void)(node);
(void)(hdr);
(void)(buf);
return true;
}
static void cb_node_connection_state_changed(struct btc_node_ *node)
{
int nb_connected = btc_node_group_amount_of_connected_nodes(node->nodegroup, NODE_CONNECTED);
node->nodegroup->log_write_cb("STATUS : connexion change status (%d node connected)\n", nb_connected);
check_connected_nodes(node->nodegroup);
}
unsigned int cb_handshake_done_bestknownheight = 0;
static void cb_handshake_done(struct btc_node_ *node)
{
int nb_connected = btc_node_group_amount_of_connected_nodes(node->nodegroup, NODE_CONNECTED);
node->nodegroup->log_write_cb("STATUS : handshake (%d node connected)\n", nb_connected);
/* make sure only one node is used for header sync */
for(size_t i =0;i< node->nodegroup->nodes->len; i++)
{
btc_node *check_node = vector_idx(node->nodegroup->nodes, i);
if ( ( (check_node->state & NODE_HEADERSYNC) == NODE_HEADERSYNC
||
(check_node->state & NODE_BLOCKSYNC) == NODE_BLOCKSYNC
)
&&
(check_node->state & NODE_CONNECTED) == NODE_CONNECTED)
return;
}
/*
* Si le nouveau noeud a une meilleur connaissance de la blockchain que nous
* On relance une synchro de la blockchain
* Si possible on repart de 20 blocks en arrière
* Cela pour éviter de rester coincés dans un fork
*
* De même, on garde une marge de manoeuvre dans les positions
* du fichier
*/
if (blockchain_fd != NULL)
{
/*
* Définir et initialiser un tampon de 20 blocks
* Ca veut dire qu'on considère qu'il n'y a pas de fork
* de plus de 20 blocks
*/
#define MARGE_TAMPON 20
char buffer[MARGE_TAMPON][65];
uint32_t read_height[MARGE_TAMPON];
uint32_t read_nb_tx[MARGE_TAMPON];
fpos_t fpos[MARGE_TAMPON];
(void) fseek(blockchain_fd, 0L, SEEK_SET);
for(uint i = 0; i < MARGE_TAMPON; i++)
{
fgetpos(blockchain_fd, fpos+i);
strcpy(buffer[i],"");
read_height[i] = 0;
}
request_headers_or_blocks_hash_init = false;
while(fscanf(blockchain_fd, "%s %d %d\n", buffer[0], read_height, read_nb_tx))
{
/* Décaler le tampon d'un cran vers le bas */
for(uint i = (MARGE_TAMPON-1); i > 0 ; i--)
{
strcpy(buffer[i], buffer[i-1]);
read_height[i] = read_height[i-1];
read_nb_tx[i] = read_nb_tx[i-1];
memcpy(fpos+i, fpos+(i-1), sizeof(fpos_t));
}
if (feof(blockchain_fd)) break;
}
if (read_height[0] > MARGE_TAMPON)
{
/*
* On se sert du haut de la pile comme point de départ
*/
int outlen;
node->nodegroup->log_write_cb("STATUS : Setting requested hash with %s\n", buffer[19]);
utils_reverse_hex(buffer[19], 64);
utils_hex_to_bin(buffer[19], request_headers_or_blocks_hash, 64, &outlen);
cb_handshake_done_bestknownheight = read_height[19];
request_headers_or_blocks_hash_init = true;
fsetpos(blockchain_fd, fpos+(MARGE_TAMPON-1));
}
}
if (node->bestknownheight > cb_handshake_done_bestknownheight)
{
node->nodegroup->log_write_cb("STATUS : starting header sync from node %d\n", node->nodeid);
node->state |= NODE_HEADERSYNC;
request_headers_or_blocks(node, false);
} else {
node->state &= ~NODE_HEADERSYNC;
}
}
int btc_header_hash_compare(uint8_t *hashA, uint8_t *hashB)
{
/* byte per byte compare */
for (unsigned int i = 0; i < sizeof(uint256); i++) {
uint8_t iA = hashA[i];
uint8_t iB = hashB[i];
if (iA > iB)
return -1;
else if (iA < iB)
return 1;
}
return 0;
}
static void post_inv_cmd(struct btc_node_ *node, struct const_buffer *buf)
{
struct const_buffer buf_copy = { buf->p, buf->len };
btc_bool contains_block = false;
uint32_t vsize;
// directly create a getdata message
cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, BTC_MSG_GETDATA, buf->p, buf->len);
if (!deser_varlen(&vsize, &buf_copy)) return;
for (unsigned int i = 0; i < vsize; i++)
{
uint8_t hash[36];
uint32_t type;
if (!deser_u32(&type, &buf_copy)) return;
if (!deser_u256(hash, &buf_copy)) return;
contains_block |= (type == BTC_INV_TYPE_BLOCK);
}
/*
* This a MSG for inventory one block
*/
if (contains_block && (vsize == 1))
{
node->time_last_request = time(NULL);
btc_node_send(node, p2p_msg);
}
/* cleanup */
cstr_free(p2p_msg, true);
}
static void cb_post_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf)
{
struct const_buffer buf_copy = { buf->p, buf->len };
uint256 hash_bin_val;
char hash_hex_str[65];
/*
* MSG is inventory
*/
if (strcmp(hdr->command, BTC_MSG_INV) == 0)
{
post_inv_cmd(node, buf);
}
/*
* MSG is block data
*/
if (strcmp(hdr->command, BTC_MSG_BLOCK) == 0)
{
FILE* block_fd;
char block_filename[2000];
char prev_hex_str[65];
btc_bool is_a_known_block = false;
const char* coinbase_hash = "0000000000000000000000000000000000000000000000000000000000000000";
btc_block_header header;
uint32_t nb_tx;
uint32_t block_height = 0;
uint64_t total_outputs = 0;
uint64_t total_fees = 0;
uint64_t reward = 5000000000;
/*
* La synchro des entêtes n'est pas terminée
* Dans ce cas on ne traite pas le bloc ...
*/
if (node->bestknownheight > cb_handshake_done_bestknownheight) return;
/*
* Désérialisation du bloc
*/
if (!btc_block_header_deserialize(&header, &buf_copy)) return;
if (!deser_varlen(&nb_tx, &buf_copy)) return;
btc_block_header_hash(&header, (uint8_t *)&hash_bin_val);
memset(hash_hex_str, 0, sizeof(hash_hex_str));
utils_bin_to_hex(hash_bin_val, sizeof(hash_bin_val), hash_hex_str);
utils_reverse_hex(hash_hex_str, 64);
memset(prev_hex_str, 0, sizeof(prev_hex_str));
utils_bin_to_hex(header.prev_block, sizeof(header.prev_block), prev_hex_str);
utils_reverse_hex(prev_hex_str, 64);
// Nous connaissons déjà ce block comme étant le sommet de la blockchain
if (0 == btc_header_hash_compare((uint8_t *)&hash_bin_val, (uint8_t *)&request_headers_or_blocks_hash)) return;
// Est-ce un nouveau sommet de la blockchain ?
if (0 == btc_header_hash_compare((uint8_t *)&header.prev_block, (uint8_t *)&request_headers_or_blocks_hash))
{
cb_handshake_done_bestknownheight += 1;
memcpy(&request_headers_or_blocks_hash, &hash_bin_val, sizeof(uint256));
block_height = cb_handshake_done_bestknownheight;
node->nodegroup->log_write_cb("STATUS : New chain top detected (height is now %d) !\n",cb_handshake_done_bestknownheight);
} else {
node->nodegroup->log_write_cb("STATUS : Orphan block detected !\n");
/*
* TODO
* Conserver une liste des blocks orphelins
* Grâce au timer, tenter de les rattacher après coup
*
* On peut recevoir un nouveau block alors que nous sommes
* en train de se sycnhroniser.
*
* Il peut également s'agir d'un début de fork.
*/
if (blockchain_fd != NULL)
{
char buffer[65];
uint32_t read_height = 0;
(void) fseek(blockchain_fd, 0L, SEEK_SET);
while(fscanf(blockchain_fd, "%s %d\n", buffer, &read_height))
{
if (!strcmp(buffer, hash_hex_str))
{
/*
* Ce block est déjà connu
*/
is_a_known_block = true;
block_height = read_height;
(void) fseek(blockchain_fd, 0L, SEEK_END);
node->nodegroup->log_write_cb("STATUS : Known block detected (%d) !\n", block_height);
break;
}
if (!strcmp(buffer, prev_hex_str))
{
/*
* Ce block est potentiellement un début de fork
* Il n'est pas au sommet
* Mais on connait son parent
*/
block_height = read_height + 1;
}
if (feof(blockchain_fd)) break;
}
(void) fseek(blockchain_fd, 0L, SEEK_END);
}
if (!is_a_known_block)
{
if (block_height > 0)
{
/*
* Ce block est potentiellement un début de fork
* On le place au sommet
* Attention :
* Je ne suis pas sûr que c'est ce qu'il faut faire ...
*/
memcpy(&request_headers_or_blocks_hash, &hash_bin_val, sizeof(uint256));
cb_handshake_done_bestknownheight = block_height;
node->nodegroup->log_write_cb("STATUS : Fork block detected (%d) !\n", block_height);
} else {
/*
* Le block a-t-il moins de 2 heures ?
*/
if (difftime(time(NULL), header.timestamp) < (2*3600))
{
/*
* Ce block est un orphelin
* TODO
* Keep in memory and use the timer to try to connect it again to the blockchain
*/
if (node->bestknownheight > cb_handshake_done_bestknownheight)
{
/*
* La synchronisation n'est pas finie
*/
node->nodegroup->log_write_cb("STATUS : Orphan block while synchro !\n");
} else {
node->nodegroup->log_write_cb("STATUS : Orphan block detected !\n");
}
}
return;
}
}
}
if (!is_a_known_block)
{
if (blockchain_fd != NULL)
{
(void) fseek(blockchain_fd, 0L, SEEK_END);
fprintf(blockchain_fd, "%s %d\n", hash_hex_str, block_height);
fflush(blockchain_fd);
}
}
if (nb_tx == 1)
{
if (emptyblock_fd != NULL)
{
(void) fseek(emptyblock_fd, 0L, SEEK_END);
fprintf(emptyblock_fd, "%s %d\n", hash_hex_str, block_height);
fflush(emptyblock_fd);
}
}
sprintf(block_filename,"%s/blocks/%u_%s", simple_db_path, block_height, hash_hex_str);
if (file_exist(block_filename)) return;
// Save the block in a file
block_fd = fopen(block_filename,"wb");
if (block_fd == NULL) return;
fwrite((const void*) &block_height, sizeof(uint32_t), 1, block_fd);
fwrite((const void*) &hash_bin_val, sizeof(uint256), 1, block_fd);
fwrite((const void*) &header.version, sizeof(int32_t), 1, block_fd);
fwrite((const void*) &header.timestamp, sizeof(uint32_t), 1, block_fd);
fwrite((const void*) &header.nonce, sizeof(uint32_t), 1, block_fd);
fwrite((const void*) &header.prev_block, sizeof(uint256), 1, block_fd);
fwrite((const void*) &header.merkle_root, sizeof(uint256), 1, block_fd);
fwrite((const void*) &nb_tx, sizeof(uint32_t), 1, block_fd);
for (unsigned int i = 0; i < nb_tx; i++)
{
uint64_t tx_total_outputs = 0;
size_t consummed = 0;
btc_tx* tx =btc_tx_new(); //needs to be on the heap
btc_tx_deserialize(buf_copy.p, buf_copy.len, tx, &consummed, true);
deser_skip(&buf_copy, consummed);
btc_tx_hash(tx, hash_bin_val);
utils_bin_to_hex(hash_bin_val, sizeof(hash_bin_val), hash_hex_str);
utils_reverse_hex(hash_hex_str, 64);
for (size_t victx = 0; victx < tx->vin->len; victx++)
{
btc_tx_in* tx_in = vector_idx(tx->vin, victx);
char* hex_txin = utils_uint8_to_hex(tx_in->prevout.hash, 32);
utils_reverse_hex(hex_txin, strlen(hex_txin));
if (!strncmp(hex_txin,coinbase_hash,strlen(coinbase_hash))) strcpy(hex_txin,"COINBASE");
}
for (size_t voctx = 0; voctx < tx->vout->len; voctx++)
{
btc_tx_out* tx_out = vector_idx(tx->vout, voctx);
tx_total_outputs += tx_out->value;
}
fwrite((const void*) &hash_bin_val, sizeof(uint256), 1, block_fd);
fwrite((const void*) &tx->locktime, sizeof(uint32_t), 1, block_fd);
fwrite((const void*) &tx_total_outputs, sizeof(uint64_t), 1, block_fd);
if (i == 0)
{
// Compute fees
while(reward > 0)
{
if (reward < tx_total_outputs)
break;
reward /= 2;
}
total_fees = tx_total_outputs - reward;
}
total_outputs += tx_total_outputs;
btc_tx_free(tx);
}
fclose(block_fd);
fflush(stdout);
}
/*
* MSG is headers data
*/
if (strcmp(hdr->command, BTC_MSG_HEADERS) == 0)
{
uint32_t amount_of_headers;
if (!deser_varlen(&amount_of_headers, &buf_copy)) return;
node->nodegroup->log_write_cb("STATUS : (%d) headers received\n", amount_of_headers);
while(amount_of_headers--)
{
uint256 hash_bin_val;
btc_block_header header;
if (!btc_block_header_deserialize(&header, &buf_copy)) return;
if (!deser_skip(&buf_copy, 1)) return;
btc_block_header_hash(&header, (uint8_t *)&hash_bin_val);
if (0 == btc_header_hash_compare((uint8_t *)&header.prev_block, (uint8_t *)&request_headers_or_blocks_hash))
{
cb_handshake_done_bestknownheight += 1;
memcpy(&request_headers_or_blocks_hash, &hash_bin_val, sizeof(uint256));
memset(hash_hex_str, 0, sizeof(hash_hex_str));
utils_bin_to_hex(hash_bin_val, sizeof(hash_bin_val), hash_hex_str);
utils_reverse_hex(hash_hex_str, 64);
if (blockchain_fd != NULL)
{
// Ne rajouter un bloc que si on ne le connait pas
char buffer[65];
uint32_t read_height;
btc_bool flag_local = false;
/*
* Cette ligen a é mise en commentaire
* Car elle ralenti énormément le processus de synchro
* Elle fait repartir du début du fichier à chaque fois.
* Pour accélérer le processus, on se cale en début de synchro (cd_handcheck_done)
* Puis on ne fait qu'avancer dans le fichier
* Attention :
* Cela suppose que le noeud nous envoie les entêtes de blocks dans l'ordre
*/
// (void) fseek(blockchain_fd, 0L, SEEK_SET);
while(fscanf(blockchain_fd, "%s %d\n", buffer, &read_height))
{
if (!strcmp(buffer, hash_hex_str))
{
flag_local = true;
break;
}
if (feof(blockchain_fd)) break;
}
if (!flag_local)
{
(void) fseek(blockchain_fd, 0L, SEEK_END);
fprintf(blockchain_fd, "%s %d\n", hash_hex_str,cb_handshake_done_bestknownheight);
}
}
} else {
node->nodegroup->log_write_cb("STATUS : Orphan block header !\n");
}
}
if (node->bestknownheight > cb_handshake_done_bestknownheight)
{
/*
* La synchronisation n'est pas finie
* Demander d'autres blocs
*/
node->nodegroup->log_write_cb("STATUS : bestknownheigt (%d / %d)\n", cb_handshake_done_bestknownheight, node->bestknownheight);
request_headers_or_blocks(node, false);
} else {
node->nodegroup->log_write_cb("STATUS : Headers sync is finished !\n", cb_handshake_done_bestknownheight, node->bestknownheight);
node->state &= ~NODE_HEADERSYNC;
if (blockchain_fd != NULL)
fflush(blockchain_fd);
// TRES TRES SALE ...
exit(0);
}
}
}
/*
* Init d'un eliste de blocs
*/
FILE* init_blocklist_file(char* filename)
{
FILE* fd = NULL;
char* blockchain_full_filename = NULL;
char buffer[65];
uint32_t block_height;
blockchain_full_filename = calloc(strlen(simple_db_path)+strlen(filename)+2, sizeof(char));
if (blockchain_full_filename == NULL) return NULL;
/*
*
* init de la liste des blocs vides
*
*/
sprintf(blockchain_full_filename,"%s/%s", simple_db_path, filename);
if (!file_exist(blockchain_full_filename))
{
fd = fopen(blockchain_full_filename,"w");
if (fd != NULL)
{
int outlen;
/*
* Init with Genesis Block
*/
sprintf(buffer, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
block_height = 0;
fprintf(fd, "%s %d\n", buffer, block_height);
fclose(fd);
fd = NULL;
utils_reverse_hex(buffer, 64);
utils_hex_to_bin(buffer, request_headers_or_blocks_hash, 64, &outlen);
request_headers_or_blocks_hash_init = true;
cb_handshake_done_bestknownheight = block_height;
}
}
fd = fopen(blockchain_full_filename,"r+");
return fd;
}
/*
* Gestion du fichier de chaine de blocks
*/
int init_blockchain_file()
{
const char* blockchain_filename = "blockchain.txt";
const char* emptyblock_filename = "emptyblocks.txt";
char* blockchain_full_filename = NULL;
char buffer[65];
uint32_t block_height;
/*
* Init de la liste des blocks vides
*/
emptyblock_fd = init_blocklist_file("emptyblocks.txt");
/*
* Init de la liste complete des blocks
*/
blockchain_fd = init_blocklist_file("blockchain.txt");
if (blockchain_fd != NULL)
{
while(fscanf(blockchain_fd, "%s %d\n", buffer, &block_height))
{
if (block_height > cb_handshake_done_bestknownheight)
{
int outlen;
utils_reverse_hex(buffer, 64);
utils_hex_to_bin(buffer, request_headers_or_blocks_hash, 64, &outlen);
request_headers_or_blocks_hash_init = true;
cb_handshake_done_bestknownheight = block_height;
}
if (feof(blockchain_fd)) break;
}
}
free(blockchain_full_filename);
return 0;
}
#define array_len(a) ( sizeof(a) / sizeof(a[0]) )
int main(int ac, char** av)
{
btc_node_group* group = NULL;
cb_file_write_log_flag = false;
cb_file_write_log_filter = "STATUS";
/*
* if parameter, change dir to this param
*/
if (ac > 1) chdir(av[1]);
/*
* Gestion du fichier de chaine de blocks
*/
if (0 != init_blockchain_file()) return 1;
/*
* Create a node group
*/
group = btc_node_group_new(NULL);
group->desired_amount_connected_nodes = 1;
group->periodic_timer_cb = cb_timer;
group->log_write_cb = cb_file_write_log;
group->parse_cmd_cb = cb_parse_cmd;
group->postcmd_cb = cb_post_cmd;
group->node_connection_state_changed_cb = cb_node_connection_state_changed;
group->handshake_done_cb = cb_handshake_done;
sprintf(group->clientstr,"TOPISTO is using libbtc");
find_and_add_nodes(group);
/* connect to the next node */
btc_node_group_connect_next_nodes(group);
/* start the event loop */
btc_node_group_event_loop(group);
/* cleanup */
btc_node_group_free(group); //will also free the nodes structures from the heap
return 0;
}

Ładowanie…
Anuluj
Zapisz