瀏覽代碼

initial import

master
MEUNIER Thibaud 5 年之前
父節點
當前提交
a43e5282c1
共有 24 個檔案被更改,包括 5553 行新增0 行删除
  1. +2
    -0
      .gitignore
  2. +39
    -0
      Makefile
  3. +27
    -0
      Makefile.inc
  4. 二進制
      data/block_614598_local
  5. 二進制
      data/block_614598_network
  6. 二進制
      data/block_buffer
  7. 二進制
      data/block_ref
  8. 二進制
      data/block_test
  9. +3359
    -0
      data/block_test.json
  10. +6
    -0
      include/daemonize.h
  11. +8
    -0
      livrer_topisto.sh
  12. +17
    -0
      src/.vscode/c_cpp_properties.json
  13. +25
    -0
      src/bidon.c
  14. +108
    -0
      src/block2json.c
  15. +67
    -0
      src/daemonize.c
  16. +290
    -0
      src/listen_blockchain.c
  17. +204
    -0
      src/net_test.c
  18. +99
    -0
      src/read_block.c
  19. +202
    -0
      src/read_block.c.bak
  20. +21
    -0
      src/signal_test.c
  21. +187
    -0
      src/spv.c
  22. +56
    -0
      src/spv_full.c
  23. +809
    -0
      src/spy.c
  24. +27
    -0
      tmp/Makefile

+ 2
- 0
.gitignore 查看文件

@ -0,0 +1,2 @@
obj/*
bin/*

+ 39
- 0
Makefile 查看文件

@ -0,0 +1,39 @@
EXE=net_test listen_blockchain spv spv_full tx read_block btcspy block2json
include Makefile.inc
$(BINDIR)/net_test : $(OBJDIR)/net_test.o
$(CC) -o $@ $^ $(LDFLAGS)
net_test : $(BINDIR)/net_test
$(BINDIR)/listen_blockchain : $(OBJDIR)/listen_blockchain.o
$(CC) -o $@ $^ $(LDFLAGS)
listen_blockchain : $(BINDIR)/listen_blockchain
$(BINDIR)/spv : $(OBJDIR)/spv.o
$(CC) -o $@ $^ $(LDFLAGS)
spv : $(BINDIR)/spv
$(BINDIR)/spv_full : $(OBJDIR)/spv_full.o
$(CC) -o $@ $^ $(LDFLAGS)
spv_full : $(BINDIR)/spv_full
$(BINDIR)/read_block : $(OBJDIR)/read_block.o
$(CC) -o $@ $^ $(LDFLAGS)
read_block : $(BINDIR)/read_block
$(BINDIR)/btcspy : $(OBJDIR)/spy.o $(OBJDIR)/daemonize.o
$(CC) -o $@ $^ $(LDFLAGS)
btcspy : $(BINDIR)/btcspy
$(BINDIR)/block2json : $(OBJDIR)/block2json.o
$(CC) -o $@ $^ $(LDFLAGS)
block2json : $(BINDIR)/block2json

+ 27
- 0
Makefile.inc 查看文件

@ -0,0 +1,27 @@
CC=gcc
IFLAGS=-I /usr/local/include/btc -I include
CFLAGS=-g
LDFLAGS=-lbtc
OBJDIR=obj
BINDIR=bin
SRCDIR=src
all: $(OBJDIR) $(BINDIR) $(EXE)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(OBJDIR)/%.o : $(SRCDIR)/%.c | $(OBJDIR) $(BINDIR)
$(CC) $(IFLAGS) -o $@ -c $< $(CFLAGS)
.PHONY: clean mrproper $(EXE)
clean:
rm -f $(OBJDIR)/*.o
mrproper : clean
rm -rf $(OBJDIR)
rm -rf $(BINDIR)

二進制
data/block_614598_local 查看文件


二進制
data/block_614598_network 查看文件


二進制
data/block_buffer 查看文件


二進制
data/block_ref 查看文件


二進制
data/block_test 查看文件


+ 3359
- 0
data/block_test.json
文件差異過大導致無法顯示
查看文件


+ 6
- 0
include/daemonize.h 查看文件

@ -0,0 +1,6 @@
#ifndef __MY_DAEMONIZE_H__
#define __MY_DAEMONIZE_H__
void daemonize();
#endif

+ 8
- 0
livrer_topisto.sh 查看文件

@ -0,0 +1,8 @@
#!/bin/bash
scp -p Makefile root@topisto.net:/root/projets/my_libbtc_tools
scp -p -r include root@topisto.net:/root/projets/my_libbtc_tools
scp -p -r src root@topisto.net:/root/projets/my_libbtc_tools
scp -p data/block_ref root@topisto.net:/root/projets/my_libbtc_tools/data

+ 17
- 0
src/.vscode/c_cpp_properties.json 查看文件

@ -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
src/bidon.c 查看文件

@ -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");
}

+ 108
- 0
src/block2json.c 查看文件

@ -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;
}

+ 67
- 0
src/daemonize.c 查看文件

@ -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));
}

+ 290
- 0
src/listen_blockchain.c 查看文件

@ -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
src/net_test.c 查看文件

@ -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;
}

+ 99
- 0
src/read_block.c 查看文件

@ -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;
}

+ 202
- 0
src/read_block.c.bak 查看文件

@ -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;
}

+ 21
- 0
src/signal_test.c 查看文件

@ -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;
}

+ 187
- 0
src/spv.c 查看文件

@ -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;
}

+ 56
- 0
src/spv_full.c 查看文件

@ -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;
}

+ 809
- 0
src/spy.c 查看文件

@ -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 é 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;
}

+ 27
- 0
tmp/Makefile 查看文件

@ -0,0 +1,27 @@
CC=gcc
IFLAGS=-I /usr/local/include/btc
CFLAGS=-g
LDFLAGS=-lbtc
OBJDIR=obj
BINDIR=bin
SRCDIR=src
all: $(OBJDIR) $(BINDIR) $(EXE)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(BINDIR):
mkdir -p $(BINDIR)
$(OBJDIR)/%.o : $(SRCDIR)/%.c | $(OBJDIR) $(BINDIR)
$(CC) $(IFLAGS) -o $@ -c $< $(CFLAGS)
.PHONY: clean mrproper $(EXE)
clean:
rm -f $(OBJDIR)/*.o
mrproper : clean
rm -rf $(OBJDIR)
rm -rf $(BINDIR)

Loading…
取消
儲存