From 8eea8bd36b87f55d14caa71b8997ef2ff494f24b Mon Sep 17 00:00:00 2001 From: edtubbs Date: Thu, 16 May 2024 13:21:59 -0500 Subject: [PATCH] headersdb_file: added chainwork to database record headersdb_file: added chainwork to load and write headersdb_file: updated chainwork check on reorg headersdb_file: updated current version for chainwork headersdb_file: updated load to connect first header tests: updated reorg_test to load and write headers --- src/headersdb_file.c | 57 +++++++++++++++++++------------------------- test/spv_tests.c | 13 +++++++++- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/headersdb_file.c b/src/headersdb_file.c index 993ae474c..49d52ccca 100644 --- a/src/headersdb_file.c +++ b/src/headersdb_file.c @@ -37,7 +37,7 @@ #include static const unsigned char file_hdr_magic[4] = {0xA8, 0xF0, 0x11, 0xC5}; /* header magic */ -static const uint32_t current_version = 2; +static const uint32_t current_version = 3; /* 3: added chainwork */ /** * "Compare two block headers by their hashes." @@ -203,7 +203,6 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file return false; } } - dogecoin_bool firstblock = true; size_t connected_headers_count = 0; if (db->headers_tree_file && !create) { @@ -213,11 +212,11 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file // print progress if (connected_headers_count % 1000 == 0) { - printf("\r%ld headers loaded", connected_headers_count); + printf("\r%ld headers loaded\n", connected_headers_count); fflush(stdout); } - uint8_t buf_all[32+4+80]; + uint8_t buf_all[32+4+32+80]; if (fread(buf_all, sizeof(buf_all), 1, db->headers_tree_file) == 1) { struct const_buffer cbuf_all = {buf_all, sizeof(buf_all)}; @@ -225,34 +224,23 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file uint256 hash; uint32_t height; + uint256 chainwork; deser_u256(hash, &cbuf_all); deser_u32(&height, &cbuf_all); + deser_u256(chainwork, &cbuf_all); dogecoin_bool connected; - if (firstblock) + + dogecoin_blockindex *pindex = dogecoin_headers_db_connect_hdr(db, &cbuf_all, true, &connected); + if (!connected) { - dogecoin_blockindex *chainheader = dogecoin_calloc(1, sizeof(dogecoin_blockindex)); - chainheader->height = height; - if (!dogecoin_block_header_deserialize(&chainheader->header, &cbuf_all, db->params, &chainheader->chainwork)) { - dogecoin_block_header_free(&chainheader->header); - dogecoin_free(chainheader); - fprintf(stderr, "\nError: Invalid data found.\n"); - return -1; - } - dogecoin_block_header_hash(&chainheader->header, (uint8_t *)&chainheader->hash); - chainheader->prev = NULL; - db->chaintip = chainheader; - firstblock = false; - } else { - dogecoin_blockindex *pindex = dogecoin_headers_db_connect_hdr(db, &cbuf_all, true, &connected); - if (!connected) - { - printf("\nConnecting header %s failed (at height: %d) read_write: %d\n", hash_to_string(hash), db->chaintip->height, db->read_write_file); - dogecoin_free(pindex); - } - else { - connected_headers_count++; - } + printf("\nConnecting header %s failed (at height: %d) read_write: %d\n", hash_to_string(hash), db->chaintip->height, db->read_write_file); + dogecoin_free(pindex); + } + else { + connected_headers_count++; } + + memcpy(db->chaintip->chainwork, chainwork, sizeof(uint256)); } } } @@ -269,9 +257,10 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file * @return Nothing. */ dogecoin_bool dogecoin_headers_db_write(dogecoin_headers_db* db, dogecoin_blockindex *blockindex) { - cstring *rec = cstr_new_sz(100); + cstring *rec = cstr_new_sz(148); // hash + height + chainwork + header ser_u256(rec, blockindex->hash); ser_u32(rec, blockindex->height); + ser_u256(rec, blockindex->chainwork); dogecoin_block_header_serialize(rec, &blockindex->header); size_t res = fwrite(rec->str, rec->len, 1, db->headers_tree_file); dogecoin_file_commit(db->headers_tree_file); @@ -357,7 +346,9 @@ dogecoin_blockindex * dogecoin_headers_db_connect_hdr(dogecoin_headers_db* db, s dogecoin_free(blockindex_chainwork); // Chain reorganization if necessary - if (fork_from_block && blockindex->height > db->chaintip->height && arith_uint256_greater_than(added_chainwork, chaintip_chainwork)) { + if (fork_from_block && blockindex->height > db->chaintip->height && + (arith_uint256_greater_than(added_chainwork, chaintip_chainwork) || + (arith_uint256_equal(added_chainwork, chaintip_chainwork) && blockindex->header.timestamp > db->chaintip->header.timestamp))) { // Identify the common ancestor dogecoin_blockindex* common_ancestor = db->chaintip; @@ -420,10 +411,6 @@ dogecoin_blockindex * dogecoin_headers_db_connect_hdr(dogecoin_headers_db* db, s db->chaintip = blockindex; } - // Free the dynamically allocated memory - dogecoin_free(chaintip_chainwork); - dogecoin_free(added_chainwork); - if (!load_process && db->read_write_file) { if (!dogecoin_headers_db_write(db, blockindex)) { @@ -434,6 +421,10 @@ dogecoin_blockindex * dogecoin_headers_db_connect_hdr(dogecoin_headers_db* db, s dogecoin_btree_tsearch(blockindex, &db->tree_root, dogecoin_header_compare); } + // Free the dynamically allocated memory + dogecoin_free(chaintip_chainwork); + dogecoin_free(added_chainwork); + if (db->max_hdr_in_mem > 0) { // de-allocate no longer required headers // keep them only on-disk diff --git a/test/spv_tests.c b/test/spv_tests.c index 7b35097fe..67ce01f9f 100644 --- a/test/spv_tests.c +++ b/test/spv_tests.c @@ -104,7 +104,7 @@ void test_reorg() { unlink(headersfile); // Initialize SPV client - dogecoin_spv_client* client = dogecoin_spv_client_new(chain, false, true, false, false, 8, NULL); + dogecoin_spv_client* client = dogecoin_spv_client_new(chain, false, false, false, false, 8, NULL); client->header_message_processed = test_spv_header_message_processed; client->sync_completed = test_spv_sync_completed; dogecoin_spv_client_load(client, headersfile, false); @@ -571,4 +571,15 @@ void test_reorg() { dogecoin_spv_client_free(client); remove_all_hashes(); remove_all_maps(); + + // Re-initialize SPV client and load the headers database + client = dogecoin_spv_client_new(chain, false, false, false, false, 8, NULL); + client->header_message_processed = test_spv_header_message_processed; + client->sync_completed = test_spv_sync_completed; + dogecoin_spv_client_load(client, headersfile, false); + + // Cleanup + dogecoin_spv_client_free(client); + remove_all_hashes(); + remove_all_maps(); }