initial import
This commit is contained in:
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"/home/tibo/projets/libbtc/include/**",
|
||||
"/home/tibo/projets/my_libbtc_tools/include"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"cStandard": "c99",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#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>
|
||||
|
||||
#include <daemonize.h>
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
printf("\nuint32_t : %ld", sizeof(uint32_t));
|
||||
printf("\nuint64_t : %ld", sizeof(uint64_t));
|
||||
printf("\n");
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#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 <btc/block.h>
|
||||
#include <btc/net.h>
|
||||
#include <btc/utils.h>
|
||||
#include <btc/serialize.h>
|
||||
#include <btc/tx.h>
|
||||
#include <btc/utils.h>
|
||||
|
||||
btc_bool read_(FILE* block_fd)
|
||||
{
|
||||
uint8_t val_uint8_t;
|
||||
uint32_t val_uint32_t;
|
||||
uint64_t val_uint64_t;
|
||||
uint256 val_uint256;
|
||||
|
||||
uint32_t nb_tx = 0;
|
||||
uint64_t amount = 0;
|
||||
uint64_t reward = 5000000000;
|
||||
uint64_t fees = 0;
|
||||
char hash_hex_str[65];
|
||||
|
||||
printf("{\n");
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(int32_t), 1, block_fd);
|
||||
printf("\n\"Height\" : \"%u\",", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\n\"Hash\" : \"%s\",", hash_hex_str);
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(int32_t), 1, block_fd);
|
||||
printf("\n\"Version\" : \"%u\",", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd);
|
||||
printf("\n\"Timestamp\" : \"%u\",", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd);
|
||||
printf("\n\"Nonce\" : \"%u\",", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\n\"Previous\" : \"%s\",", hash_hex_str);
|
||||
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\n\"Merkle\" : \"%s\",", hash_hex_str);
|
||||
|
||||
fread((void*) &nb_tx, sizeof(int32_t), 1, block_fd);
|
||||
printf("\n\"TX\" : [ ");
|
||||
|
||||
for (unsigned int i = 0; i < nb_tx; i++)
|
||||
{
|
||||
if (!fread((void*) &val_uint256, sizeof(uint256), 1, block_fd)) break;
|
||||
if (!fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd)) break;
|
||||
if (!fread((void*) &val_uint64_t, sizeof(uint64_t), 1, block_fd)) break;
|
||||
|
||||
utils_bin_to_hex((unsigned char*)val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
if (i>0) printf(",");
|
||||
printf("\n{\"Hash\":\"%s\", \"Timelock\":\"%u\",\"Amount\":\"%ju\"}", hash_hex_str, val_uint32_t, val_uint64_t);
|
||||
|
||||
amount += val_uint64_t;
|
||||
|
||||
// Compute reward and fees
|
||||
if (i == 0)
|
||||
{
|
||||
while(reward > 0)
|
||||
{
|
||||
if (reward < val_uint64_t) break;
|
||||
reward /= 2;
|
||||
}
|
||||
fees = val_uint64_t - reward;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
printf("\n],");
|
||||
printf("\n\"Amount\" : \"%ju\",", amount);
|
||||
printf("\n\"Reward\" : \"%ju\",", reward);
|
||||
printf("\n\"Fees\" : \"%ju\"", fees);
|
||||
printf("\n}\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
// Un fichier pour lire le block
|
||||
FILE* block_fd;
|
||||
|
||||
block_fd = fopen(av[1],"rb");
|
||||
if (block_fd == NULL) return 1;
|
||||
read_(block_fd);
|
||||
fclose(block_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define RUNNING_DIR "/tmp"
|
||||
#define LOCK_FILE "/tmp/daemond.lock"
|
||||
#define LOG_FILE "daemond.log"
|
||||
|
||||
/*
|
||||
* daemon.c
|
||||
*
|
||||
* Copyright 2010 Vasudev Kamath <kamathvasudev@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
void daemonize(){
|
||||
int i,lfp;
|
||||
char str[10];
|
||||
|
||||
if(getppid() == 1)
|
||||
return;
|
||||
|
||||
i = fork();
|
||||
|
||||
if(i < 0)
|
||||
exit(1);
|
||||
if(i > 0)
|
||||
exit(0);
|
||||
setsid();
|
||||
|
||||
for(i = getdtablesize(); i >= 0; --i)
|
||||
close(i);
|
||||
|
||||
i = open("/dev/null",O_RDWR);
|
||||
dup(i);
|
||||
dup(i);
|
||||
umask(022);
|
||||
|
||||
lfp = open(LOCK_FILE,O_RDWR|O_CREAT,0640);
|
||||
if(lfp < 0)
|
||||
exit(1);
|
||||
if(lockf(lfp,F_TLOCK,0) < 0)
|
||||
exit(1);
|
||||
|
||||
sprintf(str,"%d\n",getpid());
|
||||
write(lfp,str,strlen(str));
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
#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 <btc/block.h>
|
||||
#include <btc/net.h>
|
||||
#include <btc/utils.h>
|
||||
#include <btc/serialize.h>
|
||||
#include <btc/tx.h>
|
||||
|
||||
btc_node_group* group = NULL;
|
||||
|
||||
/*
|
||||
* Fermer correctement le réseau en cas d'interuption
|
||||
*/
|
||||
static void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT)
|
||||
{
|
||||
printf("\nSIGINT catched\n");
|
||||
btc_node_group_shutdown(group);
|
||||
}
|
||||
}
|
||||
|
||||
static int default_write_log(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *fp = NULL;
|
||||
btc_bool log_flag = false;
|
||||
|
||||
static int file_write_log(const char *format, ...)
|
||||
{
|
||||
if (log_flag)
|
||||
{
|
||||
if (fp == NULL) fp = fopen("log.txt","a+");
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(fp, format, args);
|
||||
va_end(args);
|
||||
} else {
|
||||
if (fp != NULL)
|
||||
{
|
||||
fclose(fp);
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nb_points = 0;
|
||||
void init_nb_points()
|
||||
{
|
||||
printf("\n");fflush(stdout);
|
||||
nb_points = 0;
|
||||
}
|
||||
|
||||
void print_point(char c)
|
||||
{
|
||||
printf("%c",c);fflush(stdout);
|
||||
nb_points += 1;
|
||||
if (nb_points == 80) init_nb_points();
|
||||
}
|
||||
|
||||
btc_bool file_exist(const char *filename)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat (filename, &buffer) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Les callbacks
|
||||
*/
|
||||
static btc_bool timer_cb(btc_node *node, uint64_t *now)
|
||||
{
|
||||
/* return true = run internal timer logic (ping, disconnect-timeout, etc.) */
|
||||
return true;
|
||||
}
|
||||
|
||||
btc_bool parse_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf)
|
||||
{
|
||||
(void)(node);
|
||||
(void)(hdr);
|
||||
(void)(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
void post_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf)
|
||||
{
|
||||
char point = '.';
|
||||
struct const_buffer buf_copy = { buf->p, buf->len };
|
||||
if (strcmp(hdr->command, BTC_MSG_INV) == 0)
|
||||
{
|
||||
point = 'i';
|
||||
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);
|
||||
}
|
||||
|
||||
/* send message */
|
||||
if (contains_block) btc_node_send(node, p2p_msg);
|
||||
|
||||
/* cleanup */
|
||||
cstr_free(p2p_msg, true);
|
||||
}
|
||||
if (strcmp(hdr->command, BTC_MSG_BLOCK) == 0)
|
||||
{
|
||||
FILE* block_fd;
|
||||
char block_filename[85];
|
||||
|
||||
const char* coinbase_hash = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
point = 'b';
|
||||
btc_block_header header;
|
||||
uint256 hash_bin_val;
|
||||
char hash_hex_str[65];
|
||||
uint32_t nb_tx;
|
||||
unsigned long total_outputs = 0;
|
||||
|
||||
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);
|
||||
|
||||
sprintf(block_filename,"data/simpledb/block_%s",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*)&(buf->len), sizeof(size_t), 1, block_fd);
|
||||
fwrite((const void*)buf->p, sizeof(char), buf->len, block_fd);
|
||||
fclose(block_fd);
|
||||
|
||||
printf("\nHash : %s", hash_hex_str);
|
||||
printf("\nVersion : %d", header.version);
|
||||
printf("\nTimestamp : %u", header.timestamp);
|
||||
printf("\nNonce : %u", header.nonce);
|
||||
|
||||
memset(hash_hex_str, 0, sizeof(hash_hex_str));
|
||||
utils_bin_to_hex(header.prev_block, sizeof(header.prev_block), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nPrev : %s", hash_hex_str);
|
||||
printf("\nNb TX : %u", nb_tx);
|
||||
|
||||
memset(hash_hex_str, 0, sizeof(hash_hex_str));
|
||||
utils_bin_to_hex(header.merkle_root, sizeof(header.merkle_root), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nMerkle : %s", hash_hex_str);
|
||||
|
||||
for (unsigned int i = 0; i < nb_tx; i++)
|
||||
{
|
||||
unsigned long 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;
|
||||
}
|
||||
|
||||
/*
|
||||
printf("\nTx : %d", i);
|
||||
printf("\n\tVersion : %d", tx->version);
|
||||
printf("\n\tLocktime : %d", tx->locktime);
|
||||
printf("\n\tHash : %s", hash_hex_str);
|
||||
printf("\n\tTotal (%ld) outputs : %ld", tx->vout->len, tx_total_outputs);
|
||||
printf("\n");
|
||||
*/
|
||||
|
||||
fflush(stdout);
|
||||
total_outputs += tx_total_outputs;
|
||||
btc_tx_free(tx);
|
||||
}
|
||||
|
||||
printf("\nTotal Block Outputs Amount : %ld", total_outputs);
|
||||
printf("\n");
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
// print_point(point);
|
||||
}
|
||||
|
||||
void node_connection_state_changed(struct btc_node_ *node)
|
||||
{
|
||||
int nb_connected = btc_node_group_amount_of_connected_nodes(node->nodegroup, NODE_CONNECTED);
|
||||
/*
|
||||
init_nb_points();
|
||||
printf("STATUS : connexion change status (%d node connected)\n", nb_connected);
|
||||
*/
|
||||
(void)(node);
|
||||
}
|
||||
|
||||
void handshake_done(struct btc_node_ *node)
|
||||
{
|
||||
int nb_connected = btc_node_group_amount_of_connected_nodes(node->nodegroup, NODE_CONNECTED);
|
||||
init_nb_points();
|
||||
// printf("STATUS : connexion change status (%d node connected)\n", nb_connected);
|
||||
}
|
||||
|
||||
void do_the_main_job()
|
||||
{
|
||||
const btc_dns_seed seed = btc_chainparams_main.dnsseeds[0];
|
||||
vector* ips;
|
||||
|
||||
/* create a node group */
|
||||
group = btc_node_group_new(NULL);
|
||||
group->desired_amount_connected_nodes = 1;
|
||||
group->periodic_timer_cb = timer_cb;
|
||||
group->log_write_cb = file_write_log;
|
||||
group->parse_cmd_cb = parse_cmd;
|
||||
group->postcmd_cb = post_cmd;
|
||||
group->node_connection_state_changed_cb = node_connection_state_changed;
|
||||
group->handshake_done_cb = handshake_done;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
if (signal(SIGINT, sig_handler) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGINT\n");
|
||||
return 1;
|
||||
}
|
||||
init_nb_points();
|
||||
do_the_main_job();
|
||||
return 0;
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
#include <btc/block.h>
|
||||
#include <btc/net.h>
|
||||
#include <btc/utils.h>
|
||||
#include <btc/serialize.h>
|
||||
#include <btc/tx.h>
|
||||
|
||||
static btc_bool timer_cb(btc_node *node, uint64_t *now)
|
||||
{
|
||||
/*
|
||||
if (node->time_started_con + 300 < *now)
|
||||
btc_node_disconnect(node);
|
||||
*/
|
||||
/* return true = run internal timer logic (ping, disconnect-timeout, etc.) */
|
||||
return true;
|
||||
}
|
||||
|
||||
static int default_write_log(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
va_end(args);
|
||||
return 1;
|
||||
}
|
||||
|
||||
btc_bool parse_cmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf)
|
||||
{
|
||||
(void)(node);
|
||||
(void)(hdr);
|
||||
(void)(buf);
|
||||
return true;
|
||||
}
|
||||
|
||||
void postcmd(struct btc_node_ *node, btc_p2p_msg_hdr *hdr, struct const_buffer *buf)
|
||||
{
|
||||
if (strcmp(hdr->command, "block") == 0)
|
||||
{
|
||||
btc_block_header header;
|
||||
if (!btc_block_header_deserialize(&header, buf)) return;
|
||||
|
||||
uint32_t vsize;
|
||||
if (!deser_varlen(&vsize, buf)) return;
|
||||
|
||||
for (unsigned int i = 0; i < vsize; i++)
|
||||
{
|
||||
btc_tx *tx = btc_tx_new(); //needs to be on the heep
|
||||
btc_tx_deserialize(buf->p, buf->len, tx, NULL, true);
|
||||
|
||||
btc_tx_free(tx);
|
||||
}
|
||||
|
||||
btc_node_disconnect(node);
|
||||
}
|
||||
|
||||
if (strcmp(hdr->command, "inv") == 0)
|
||||
{
|
||||
// directly create a getdata message
|
||||
cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, "getdata", buf->p, buf->len);
|
||||
|
||||
uint32_t vsize;
|
||||
uint8_t hash[36];
|
||||
uint32_t type;
|
||||
if (!deser_varlen(&vsize, buf)) return;
|
||||
|
||||
for (unsigned int i = 0; i < vsize; i++)
|
||||
{
|
||||
if (!deser_u32(&type, buf)) return;
|
||||
if (!deser_u256(hash, buf)) return;
|
||||
|
||||
}
|
||||
|
||||
/* send message */
|
||||
btc_node_send(node, p2p_msg);
|
||||
|
||||
/* cleanup */
|
||||
cstr_free(p2p_msg, true);
|
||||
}
|
||||
|
||||
if (strcmp(hdr->command, "headers") == 0)
|
||||
{
|
||||
/* send getblock command */
|
||||
|
||||
/* request some headers (from the genesis block) */
|
||||
vector *blocklocators = vector_new(1, NULL);
|
||||
uint256 from_hash;
|
||||
utils_uint256_sethex("000000000000000001e67f0781f5e31a62863e6d7a1a1f786c7f666a9954a648", from_hash); // height 428694
|
||||
uint256 stop_hash;
|
||||
utils_uint256_sethex("00000000000000000378be785f464ef19243baba187cb3791ac92a69ca46bb46", stop_hash); // height 428695
|
||||
|
||||
vector_add(blocklocators, from_hash);
|
||||
|
||||
cstring *getheader_msg = cstr_new_sz(256);
|
||||
btc_p2p_msg_getheaders(blocklocators, stop_hash, getheader_msg);
|
||||
|
||||
/* create p2p message */
|
||||
cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, "getblocks", getheader_msg->str, getheader_msg->len);
|
||||
cstr_free(getheader_msg, true);
|
||||
|
||||
/* send message */
|
||||
btc_node_send(node, p2p_msg);
|
||||
|
||||
/* cleanup */
|
||||
vector_free(blocklocators, true);
|
||||
cstr_free(p2p_msg, true);
|
||||
}
|
||||
}
|
||||
|
||||
void node_connection_state_changed(struct btc_node_ *node)
|
||||
{
|
||||
(void)(node);
|
||||
}
|
||||
|
||||
void handshake_done(struct btc_node_ *node)
|
||||
{
|
||||
/* 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)
|
||||
return;
|
||||
}
|
||||
|
||||
// request some headers (from the genesis block)
|
||||
vector *blocklocators = vector_new(1, NULL);
|
||||
vector_add(blocklocators, (void *)node->nodegroup->chainparams->genesisblockhash);
|
||||
|
||||
cstring *getheader_msg = cstr_new_sz(256);
|
||||
btc_p2p_msg_getheaders(blocklocators, NULL, getheader_msg);
|
||||
|
||||
/* create p2p message */
|
||||
cstring *p2p_msg = btc_p2p_message_new(node->nodegroup->chainparams->netmagic, "getheaders", getheader_msg->str, getheader_msg->len);
|
||||
cstr_free(getheader_msg, true);
|
||||
|
||||
/* send message */
|
||||
node->state |= NODE_HEADERSYNC;
|
||||
btc_node_send(node, p2p_msg);
|
||||
|
||||
/* cleanup */
|
||||
vector_free(blocklocators, true);
|
||||
cstr_free(p2p_msg, true);
|
||||
}
|
||||
|
||||
void test_net_basics_plus_download_block()
|
||||
{
|
||||
|
||||
vector *ips = vector_new(10, free);
|
||||
const btc_dns_seed seed = btc_chainparams_main.dnsseeds[0];
|
||||
|
||||
btc_get_peers_from_dns(seed.domain, ips, btc_chainparams_main.default_port, AF_INET);
|
||||
for (unsigned int i = 0; i<ips->len; i++)
|
||||
{
|
||||
char *ip = (char *)vector_idx(ips, i);
|
||||
printf("dns seed ip %d: %s\n", i, ip);
|
||||
}
|
||||
vector_free(ips, true);
|
||||
|
||||
/* create a invalid node */
|
||||
btc_node *node_wrong = btc_node_new();
|
||||
btc_node_set_ipport(node_wrong, "0.0.0.1:1");
|
||||
|
||||
/* create a invalid node to will run directly into a timeout */
|
||||
btc_node *node_timeout_direct = btc_node_new();
|
||||
btc_node_set_ipport(node_timeout_direct, "127.0.0.1:1234");
|
||||
|
||||
/* create a invalid node to will run indirectly into a timeout */
|
||||
btc_node *node_timeout_indirect = btc_node_new();
|
||||
btc_node_set_ipport(node_timeout_indirect, "8.8.8.8:8333");
|
||||
|
||||
/* create a node */
|
||||
btc_node *node = btc_node_new();
|
||||
btc_node_set_ipport(node, "192.99.8.123:8333");
|
||||
|
||||
/* create a node group */
|
||||
btc_node_group* group = btc_node_group_new(NULL);
|
||||
group->desired_amount_connected_nodes = 1;
|
||||
|
||||
/* add the node to the group */
|
||||
btc_node_group_add_node(group, node);
|
||||
|
||||
/* set the timeout callback */
|
||||
group->periodic_timer_cb = timer_cb;
|
||||
|
||||
/* set a individual log print function */
|
||||
group->log_write_cb = net_write_log_printf;
|
||||
group->parse_cmd_cb = parse_cmd;
|
||||
group->postcmd_cb = postcmd;
|
||||
group->node_connection_state_changed_cb = node_connection_state_changed;
|
||||
group->handshake_done_cb = handshake_done;
|
||||
|
||||
/* 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
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
test_net_basics_plus_download_block();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
#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 <btc/block.h>
|
||||
#include <btc/net.h>
|
||||
#include <btc/utils.h>
|
||||
#include <btc/serialize.h>
|
||||
#include <btc/tx.h>
|
||||
#include <btc/utils.h>
|
||||
|
||||
btc_bool file_exist(const char *filename)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat (filename, &buffer) == 0);
|
||||
}
|
||||
|
||||
btc_bool read_(FILE* block_fd)
|
||||
{
|
||||
uint8_t val_uint8_t;
|
||||
uint32_t val_uint32_t;
|
||||
uint64_t val_uint64_t;
|
||||
uint256 val_uint256;
|
||||
|
||||
uint32_t nb_tx = 0;
|
||||
uint64_t amount = 0;
|
||||
char hash_hex_str[65];
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(int32_t), 1, block_fd);
|
||||
printf("\nHeight : %u", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nHash : %s", hash_hex_str);
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(int32_t), 1, block_fd);
|
||||
printf("\nVersion : %u", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd);
|
||||
printf("\nTimestamp : %u", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd);
|
||||
printf("\nNonce : %u", val_uint32_t);
|
||||
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nPrevious : %s", hash_hex_str);
|
||||
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nMerkle : %s", hash_hex_str);
|
||||
|
||||
fread((void*) &nb_tx, sizeof(int32_t), 1, block_fd);
|
||||
printf("\nNb TX : %u", nb_tx);
|
||||
|
||||
for (unsigned int i = 0; i < nb_tx; i++)
|
||||
{
|
||||
if (!fread((void*) &val_uint256, sizeof(uint256), 1, block_fd)) break;
|
||||
if (!fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd)) break;
|
||||
if (!fread((void*) &val_uint64_t, sizeof(uint64_t), 1, block_fd)) break;
|
||||
|
||||
utils_bin_to_hex((unsigned char*)val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\n\t%u %s %u %ju", i, hash_hex_str, val_uint32_t, val_uint64_t);
|
||||
|
||||
amount += val_uint64_t;
|
||||
}
|
||||
|
||||
printf("\nTotal Block Outputs Amount : %ju", amount);
|
||||
printf("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
btc_bool write_(FILE* block_fd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
// Un fichier pour lire le block
|
||||
FILE* block_fd;
|
||||
|
||||
block_fd = fopen(av[1],"rb");
|
||||
if (block_fd == NULL) return 1;
|
||||
read_(block_fd);
|
||||
fclose(block_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
#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 <btc/block.h>
|
||||
#include <btc/net.h>
|
||||
#include <btc/utils.h>
|
||||
#include <btc/serialize.h>
|
||||
#include <btc/tx.h>
|
||||
|
||||
btc_bool file_exist(const char *filename)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat (filename, &buffer) == 0);
|
||||
}
|
||||
|
||||
btc_bool read_(FILE* block_fd)
|
||||
{
|
||||
uint32_t val_uint32_t;
|
||||
uint64_t val_uint64_t;
|
||||
uint256 val_uint256;
|
||||
uint32_t nb_tx;
|
||||
char hash_hex_str[65];
|
||||
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nHash : %s", hash_hex_str);
|
||||
fread((void*) &val_uint32_t, sizeof(int32_t), 1, block_fd);
|
||||
printf("\nVersion : %u", val_uint32_t);
|
||||
fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd);
|
||||
printf("\nTimestamp : %u", val_uint32_t);
|
||||
fread((void*) &val_uint32_t, sizeof(uint32_t), 1, block_fd);
|
||||
printf("\nNonce : %u", val_uint32_t);
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nPrevious : %s", hash_hex_str);
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nMerkle : %s", hash_hex_str);
|
||||
fread((void*) &nb_tx, sizeof(uint32_t), 1, block_fd);
|
||||
printf("\nNonce : %u", val_uint32_t);
|
||||
|
||||
while(nb_tx--)
|
||||
{
|
||||
fread((void*) &val_uint256, sizeof(uint256), 1, block_fd);
|
||||
fread((void*) &val_uint32_t, sizeof(int32_t), 1, block_fd);
|
||||
fread((void*) &val_uint64_t, sizeof(uint64_t), 1, block_fd);
|
||||
|
||||
utils_bin_to_hex(val_uint256, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\n\t%s %u %lu", hash_hex_str, val_uint32_t, val_uint64_t);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
btc_bool write_(FILE* block_fd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
// Un buffer pour stocker le block en mémoire
|
||||
void* ptr = NULL;
|
||||
struct const_buffer buf;
|
||||
|
||||
// Un fichier pour lire le block
|
||||
FILE* block_fd;
|
||||
char block_filename[85];
|
||||
|
||||
const char* coinbase_hash = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
btc_block_header header;
|
||||
uint256 hash_bin_val;
|
||||
char hash_hex_str[65];
|
||||
uint32_t nb_tx = 0;
|
||||
unsigned long total_outputs = 0;
|
||||
btc_tx *tx;
|
||||
|
||||
block_fd = fopen(av[1],"rb");
|
||||
if (block_fd == NULL) return 1;
|
||||
fread((void*)&(buf.len), sizeof(size_t), 1, block_fd);
|
||||
ptr = calloc(sizeof(char), buf.len);
|
||||
buf.p = ptr;
|
||||
fread((void*)buf.p, sizeof(char), buf.len, block_fd);
|
||||
fclose(block_fd);
|
||||
|
||||
if (!btc_block_header_deserialize(&header, &buf)) return 1;
|
||||
if (!deser_varlen(&nb_tx, &buf)) return 1;
|
||||
|
||||
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);
|
||||
|
||||
sprintf(block_filename,"data/simpledb/block_%s",hash_hex_str);
|
||||
if (file_exist(block_filename)) unlink(block_filename);
|
||||
|
||||
// Save the block in a file
|
||||
block_fd = fopen(block_filename,"wb");
|
||||
if (block_fd == NULL) return 1;
|
||||
|
||||
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);
|
||||
|
||||
printf("\nHash : %s", hash_hex_str);
|
||||
printf("\nVersion : %d", header.version);
|
||||
printf("\nTimestamp : %u", header.timestamp);
|
||||
printf("\nNonce : %u", header.nonce);
|
||||
|
||||
memset(hash_hex_str, 0, sizeof(hash_hex_str));
|
||||
utils_bin_to_hex(header.prev_block, sizeof(header.prev_block), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nPrev : %s", hash_hex_str);
|
||||
printf("\nNb TX : %d", nb_tx);
|
||||
|
||||
memset(hash_hex_str, 0, sizeof(hash_hex_str));
|
||||
utils_bin_to_hex(header.merkle_root, sizeof(header.merkle_root), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\nMerkle : %s", hash_hex_str);
|
||||
|
||||
for (unsigned int i = 0; i < nb_tx; i++)
|
||||
{
|
||||
int64_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.p, buf.len, tx, &consummed, true);
|
||||
buf.p += consummed;
|
||||
btc_tx_hash(tx, hash_bin_val);
|
||||
|
||||
fwrite((const void*) &hash_bin_val, sizeof(uint256), 1, block_fd);
|
||||
fwrite((const void*) &tx->locktime, sizeof(uint32_t), 1, block_fd);
|
||||
//printf("\nTx : %d", i);
|
||||
//printf("\n\tVersion : %d", tx->version);
|
||||
//printf("\n\tLocktime : %d", tx->locktime);
|
||||
|
||||
utils_bin_to_hex(hash_bin_val, sizeof(hash_bin_val), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
printf("\n\t%s", hash_hex_str);
|
||||
|
||||
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");
|
||||
// printf("\n\t\tInput %lu :\n\t\t\tHash : %s\n\t\t\tOutput : %d", victx, hex_txin, tx_in->prevout.n);
|
||||
}
|
||||
|
||||
for (size_t voctx = 0; voctx < tx->vout->len; voctx++)
|
||||
{
|
||||
btc_tx_out* tx_out = vector_idx(tx->vout, voctx);
|
||||
|
||||
// printf("\n\t\tOutput %lu :\n\t\t\tAmount : %ld", voctx, tx_out->value);
|
||||
tx_total_outputs += tx_out->value;
|
||||
}
|
||||
fwrite((const void*) &tx_total_outputs, sizeof(uint64_t), 1, block_fd);
|
||||
|
||||
//printf("\n\tTotal (%ld) outputs : %ld", tx->vout->len, tx_total_outputs);
|
||||
//printf("\n");
|
||||
printf(" %ld %d", tx_total_outputs, tx->locktime);
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
total_outputs += tx_total_outputs;
|
||||
|
||||
btc_tx_free(tx);
|
||||
}
|
||||
|
||||
printf("\nTotal Block Outputs Amount : %ld", total_outputs);
|
||||
printf("\n");
|
||||
|
||||
free(ptr);
|
||||
|
||||
fflush(stdout);
|
||||
fclose(block_fd);
|
||||
|
||||
// Read the block from a file
|
||||
block_fd = fopen(block_filename,"rb");
|
||||
if (block_fd == NULL) return 1;
|
||||
read_(block_fd);
|
||||
fclose(block_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include<stdlib.h>
|
||||
#include<stdio.h>
|
||||
#include<signal.h>
|
||||
#include<unistd.h>
|
||||
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT)
|
||||
printf("\nSIGINT catched\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
if (signal(SIGINT, sig_handler) == SIG_ERR)
|
||||
printf("\ncan't catch SIGINT\n");
|
||||
// A long long wait so that we can easily issue a signal to this process
|
||||
while(1)
|
||||
sleep(1);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
#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 <btc/block.h>
|
||||
#include <btc/net.h>
|
||||
#include <btc/netspv.h>
|
||||
#include <btc/utils.h>
|
||||
|
||||
btc_spv_client* spv_global_client;
|
||||
|
||||
/*
|
||||
* Fermer correctement le réseau en cas d'interuption
|
||||
*/
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT)
|
||||
{
|
||||
printf("\nSIGINT catched\n");
|
||||
fflush(stdout);
|
||||
btc_node_group_shutdown(spv_global_client->nodegroup);
|
||||
sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Informer de la consommation mémoire du processus
|
||||
*/
|
||||
void print_mem_usage()
|
||||
{
|
||||
struct rusage r_usage;
|
||||
getrusage(RUSAGE_SELF,&r_usage);
|
||||
printf("Memory usage: %ld kilobytes\n",r_usage.ru_maxrss);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
btc_bool file_exist(const char *filename)
|
||||
{
|
||||
struct stat buffer;
|
||||
return (stat (filename, &buffer) == 0);
|
||||
}
|
||||
|
||||
btc_bool write_blockindex(btc_blockindex* blockindex)
|
||||
{
|
||||
FILE* block_fd = NULL;
|
||||
char block_filename[2000];
|
||||
char hash_hex_str[65];
|
||||
|
||||
utils_bin_to_hex(blockindex->hash, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
|
||||
sprintf(block_filename,"data/simpledb/block_%u_%s",blockindex->height, hash_hex_str);
|
||||
if (file_exist(block_filename)) return false;
|
||||
|
||||
// Save the block in a file
|
||||
block_fd = fopen(block_filename,"wb");
|
||||
if (block_fd == NULL) return false;
|
||||
|
||||
fwrite((const void*) &blockindex->height, sizeof(uint32_t), 1, block_fd);
|
||||
fwrite((const void*) &blockindex->hash, sizeof(uint256), 1, block_fd);
|
||||
fwrite((const void*) &blockindex->header.version, sizeof(int32_t), 1, block_fd);
|
||||
fwrite((const void*) &blockindex->header.timestamp, sizeof(uint32_t), 1, block_fd);
|
||||
fwrite((const void*) &blockindex->header.nonce, sizeof(uint32_t), 1, block_fd);
|
||||
fwrite((const void*) &blockindex->header.prev_block, sizeof(uint256), 1, block_fd);
|
||||
fwrite((const void*) &blockindex->header.merkle_root, sizeof(uint256), 1, block_fd);
|
||||
|
||||
fclose(block_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
btc_bool add_blockindex_tx(btc_blockindex* blockindex, btc_tx* tx)
|
||||
{
|
||||
FILE* block_fd = NULL;
|
||||
char block_filename[2000];
|
||||
char hash_hex_str[65];
|
||||
uint256 hash_bin_val;
|
||||
uint64_t tx_amount = 0;
|
||||
|
||||
utils_bin_to_hex(blockindex->hash, sizeof(uint256), hash_hex_str);
|
||||
utils_reverse_hex(hash_hex_str, 64);
|
||||
|
||||
btc_tx_hash(tx, hash_bin_val);
|
||||
|
||||
for (size_t voctx = 0; voctx < tx->vout->len; voctx++)
|
||||
{
|
||||
btc_tx_out* tx_out = vector_idx(tx->vout, voctx);
|
||||
tx_amount += tx_out->value;
|
||||
}
|
||||
|
||||
sprintf(block_filename,"data/simpledb/block_%u_%s",blockindex->height, hash_hex_str);
|
||||
if (!file_exist(block_filename)) write_blockindex(blockindex);
|
||||
|
||||
// Save the block in a file
|
||||
block_fd = fopen(block_filename,"ab");
|
||||
if (block_fd == NULL) return false;
|
||||
|
||||
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_amount, sizeof(uint64_t), 1, block_fd);
|
||||
|
||||
fclose(block_fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback de fin de synchro
|
||||
*/
|
||||
void test_spv_sync_completed(btc_spv_client* client)
|
||||
{
|
||||
UNUSED(client);
|
||||
|
||||
printf("\nSync completed, at height %d\n", client->headers_db->getchaintip(client->headers_db_ctx)->height);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback de message "header"
|
||||
*/
|
||||
btc_bool test_spv_header_message_processed(struct btc_spv_client_ *client, btc_node *node, btc_blockindex *newtip)
|
||||
{
|
||||
UNUSED(client);
|
||||
UNUSED(node);
|
||||
|
||||
printf("\nGet SPV Header message\n");
|
||||
if (newtip) {
|
||||
printf("\nNew headers tip height %d\n", newtip->height);
|
||||
}
|
||||
fflush(stdout);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback de nouveau dernier block connu
|
||||
*/
|
||||
void test_spv_header_connected(struct btc_spv_client_ *client)
|
||||
{
|
||||
btc_blockindex* blockindex = client->headers_db->getchaintip(client->headers_db_ctx);
|
||||
write_blockindex(blockindex);
|
||||
printf("\nSPV Header Connected : %d\n", blockindex->height);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback de nouvelle transaction dans le dernier block connu
|
||||
*/
|
||||
void test_spv_sync_transaction(void *ctx, btc_tx *tx, unsigned int pos, btc_blockindex *blockindex)
|
||||
{
|
||||
UNUSED(ctx);
|
||||
UNUSED(pos);
|
||||
|
||||
add_blockindex_tx(blockindex, tx);
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
/*
|
||||
if (signal(SIGINT, sig_handler) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGINT\n");
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
spv_global_client = btc_spv_client_new(&btc_chainparams_main, false, false);
|
||||
spv_global_client->header_message_processed = test_spv_header_message_processed;
|
||||
spv_global_client->sync_completed = test_spv_sync_completed;
|
||||
spv_global_client->header_connected = test_spv_header_connected;
|
||||
spv_global_client->sync_transaction = test_spv_sync_transaction;
|
||||
|
||||
btc_spv_client_load(spv_global_client, "data/index.db");
|
||||
|
||||
printf("Discover peers...");
|
||||
btc_spv_client_discover_peers(spv_global_client, NULL);
|
||||
printf("done\n");
|
||||
printf("Start interacting with the p2p network...\n");
|
||||
btc_spv_client_runloop(spv_global_client);
|
||||
btc_spv_client_free(spv_global_client);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <btc/block.h>
|
||||
#include <btc/net.h>
|
||||
#include <btc/netspv.h>
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void print_mem_usage()
|
||||
{
|
||||
struct rusage r_usage;
|
||||
getrusage(RUSAGE_SELF,&r_usage);
|
||||
printf("Memory usage: %ld kilobytes\n",r_usage.ru_maxrss);
|
||||
}
|
||||
|
||||
void test_spv_sync_completed(btc_spv_client* client) {
|
||||
print_mem_usage();
|
||||
printf("Sync completed, at height %d\n", client->headers_db->getchaintip(client->headers_db_ctx)->height);
|
||||
// btc_node_group_shutdown(client->nodegroup);
|
||||
}
|
||||
|
||||
btc_bool test_spv_header_message_processed(struct btc_spv_client_ *client, btc_node *node, btc_blockindex *newtip) {
|
||||
UNUSED(client);
|
||||
UNUSED(node);
|
||||
printf("Get SPV Header message\n");
|
||||
if (newtip) {
|
||||
printf("New headers tip height %d\n", newtip->height);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void test_netspv()
|
||||
{
|
||||
// unlink("headers.db");
|
||||
btc_spv_client* client = btc_spv_client_new(&btc_chainparams_main, false, false);
|
||||
client->header_message_processed = test_spv_header_message_processed;
|
||||
client->sync_completed = test_spv_sync_completed;
|
||||
client->use_checkpoints = false; // Start from genesis
|
||||
|
||||
btc_spv_client_load(client, "data/full.db");
|
||||
|
||||
printf("Discover peers...");
|
||||
btc_spv_client_discover_peers(client, NULL);
|
||||
printf("done\n");
|
||||
printf("Start interacting with the p2p network...\n");
|
||||
btc_spv_client_runloop(client);
|
||||
btc_spv_client_free(client);
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
print_mem_usage();
|
||||
test_netspv();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,809 @@
|
||||
#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>
|
||||
|
||||
#include <daemonize.h>
|
||||
|
||||
/*
|
||||
* Les variables globales
|
||||
*/
|
||||
char* simple_db_path = "data/simpledb";
|
||||
FILE* blockchain_fd = NULL;
|
||||
|
||||
/*
|
||||
* Les outils
|
||||
*/
|
||||
static void signal_handler(int sig){
|
||||
switch(sig){
|
||||
case SIGUSR1:
|
||||
// signal USR1
|
||||
break;
|
||||
case SIGUSR2:
|
||||
// Signal USR2
|
||||
break;
|
||||
case SIGHUP:
|
||||
// Reload conf and reinitialize processus
|
||||
break;
|
||||
case SIGINT:
|
||||
// CTRL+C
|
||||
case SIGTERM:
|
||||
// Terminate : kill -15
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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 (node->bestknownheight > cb_handshake_done_bestknownheight)
|
||||
{
|
||||
if (blockchain_fd != NULL)
|
||||
{
|
||||
/*
|
||||
* Définir et intialiser un tampon de 20 blocks
|
||||
*/
|
||||
#define MARGE_TAMPON 25
|
||||
char buffer[MARGE_TAMPON][65];
|
||||
uint32_t read_height[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\n", buffer[0], read_height))
|
||||
{
|
||||
/* 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];
|
||||
memcpy(fpos+i, fpos+(i-1), sizeof(fpos_t));
|
||||
}
|
||||
|
||||
if (feof(blockchain_fd)) break;
|
||||
}
|
||||
if (read_height[0] > MARGE_TAMPON)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 été 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Gestion du fichier de chaine de blocks
|
||||
*/
|
||||
int init_blockchain_file()
|
||||
{
|
||||
const char* blockchain_filename = "blockchain.txt";
|
||||
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;
|
||||
|
||||
sprintf(blockchain_full_filename,"%s/%s", simple_db_path, blockchain_filename);
|
||||
|
||||
if (!file_exist(blockchain_full_filename))
|
||||
{
|
||||
blockchain_fd = fopen(blockchain_full_filename,"w");
|
||||
if (blockchain_fd != NULL)
|
||||
{
|
||||
int outlen;
|
||||
|
||||
/*
|
||||
* Init with Genesis Block
|
||||
*/
|
||||
sprintf(buffer, "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
|
||||
block_height = 0;
|
||||
|
||||
fprintf(blockchain_fd, "%s %d\n", buffer, block_height);
|
||||
fclose(blockchain_fd);
|
||||
blockchain_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;
|
||||
|
||||
fclose(blockchain_fd);
|
||||
blockchain_fd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
blockchain_fd = fopen(blockchain_full_filename,"r+");
|
||||
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;
|
||||
}
|
||||
|
||||
int main(int ac, char** av)
|
||||
{
|
||||
btc_node_group* group = NULL;
|
||||
|
||||
cb_file_write_log_flag = false;
|
||||
cb_file_write_log_filter = "STATUS";
|
||||
|
||||
/*
|
||||
* Daemonize
|
||||
*/
|
||||
daemonize();
|
||||
|
||||
/*
|
||||
* Trapper les signaux pour fermer correctement le programme
|
||||
*/
|
||||
if (signal(SIGCHLD,SIG_IGN) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGCHLD\n");
|
||||
return 1;
|
||||
}
|
||||
if (signal(SIGTSTP,SIG_IGN) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGTSTP\n");
|
||||
return 1;
|
||||
}
|
||||
if (signal(SIGTTOU,SIG_IGN) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGTTOU\n");
|
||||
return 1;
|
||||
}
|
||||
if (signal(SIGTTIN,SIG_IGN) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGTTIN\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (signal(SIGHUP,signal_handler) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGHUP\n");
|
||||
return 1;
|
||||
}
|
||||
if (signal(SIGTERM,signal_handler) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGTERM\n");
|
||||
return 1;
|
||||
}
|
||||
if (signal(SIGINT, signal_handler) == SIG_ERR)
|
||||
{
|
||||
printf("\ncan't catch SIGINT\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gestion du fichier de chaine de blocks
|
||||
*/
|
||||
if (ac > 1) simple_db_path = av[1];
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user