diff --git a/src/headersdb_file.c b/src/headersdb_file.c index 993ae474c..a3a87779f 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." @@ -217,7 +217,7 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file 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,8 +225,10 @@ 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) { @@ -253,6 +255,7 @@ dogecoin_bool dogecoin_headers_db_load(dogecoin_headers_db* db, const char *file connected_headers_count++; } } + memcpy(db->chaintip->chainwork, chainwork, sizeof(uint256)); } } } @@ -269,9 +272,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); @@ -307,6 +311,7 @@ dogecoin_blockindex * dogecoin_headers_db_connect_hdr(dogecoin_headers_db* db, s dogecoin_blockindex *block = dogecoin_headersdb_find(db, blockindex->hash); if (block) { // Block header already in database, return blockindex + *connected = true; return blockindex; } @@ -357,7 +362,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 +427,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 +437,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..bf1e692c9 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); @@ -555,7 +555,10 @@ void test_reorg() { dogecoin_headers_db_connect_hdr(db, &cbuf_header5_fork_again, false, &connected); u_assert_true (connected); dogecoin_free(dogecoin_headers_db_connect_hdr(db, &cbuf_header5_fork_duplicate, false, &connected)); - u_assert_true (!connected); + u_assert_true (connected); + + // Load the headers to ensure they are recorded correctly + dogecoin_spv_client_load(client, headersfile, false); // Cleanup cstr_free(cbuf_all, true);