From cd3c3ad07d8d507fcf8fb480d00cab7768ed29be Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sat, 25 Jul 2026 23:31:36 +0300 Subject: [PATCH] merkle_sync: fix level 0 SQL range, rebuild trees at startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - _get_level_hashes: use separate SQL without prefix64<=? for level 0. UINT64_MAX cast to sqlite3_int64 becomes -1, making prefix64<=-1 always false for positive prefixes → bitmap always 0 → sync never exchanges data. - member_sync_init: add _rebuild_all_trees to scan all peers_* tables and call merkle_sync_recompute_path for each member. Ensures merkle_tree_hash has entries for members added before merkle sync existed. --- tools/chatgui/transport/member_sync.c | 25 +++++++++++++++++++++++++ tools/chatgui/transport/merkle_sync.c | 21 ++++++++++++--------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/tools/chatgui/transport/member_sync.c b/tools/chatgui/transport/member_sync.c index 072efaf5..6ea08ec1 100644 --- a/tools/chatgui/transport/member_sync.c +++ b/tools/chatgui/transport/member_sync.c @@ -306,11 +306,36 @@ static const struct merkle_sync_data_ops g_member_ops = { /* ── Public API ── */ +static void _rebuild_all_trees(struct UTUN_INSTANCE* inst) { + sqlite3* db = _db(inst); if (!db) return; + sqlite3_stmt* st = NULL; + if (sqlite3_prepare_v2(db, + "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE 'peers_%'", + -1, &st, NULL) != SQLITE_OK) return; + while (sqlite3_step(st) == SQLITE_ROW) { + const char* tbl = (const char*)sqlite3_column_text(st, 0); + if (!tbl || strncmp(tbl, "peers_", 6) != 0) continue; + const char* ch_id = tbl + 6; + sqlite3_stmt* ns = NULL; + char sql[256]; snprintf(sql, sizeof(sql), "SELECT node_id FROM \"%s\"", tbl); + if (sqlite3_prepare_v2(db, sql, -1, &ns, NULL) == SQLITE_OK) { + while (sqlite3_step(ns) == SQLITE_ROW) { + uint64_t nid = (uint64_t)sqlite3_column_int64(ns, 0); + merkle_sync_recompute_path(inst, ch_id, nid); + DEBUG_DEBUG(DEBUG_CATEGORY_DB_SYNC, "%s: rebuild tree ns=%s nid=%016llx", MS_ID, ch_id, (unsigned long long)nid); + } + sqlite3_finalize(ns); + } + } + sqlite3_finalize(st); +} + int member_sync_init(struct UTUN_INSTANCE* inst) { if (!inst) return -1; DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: init", MS_ID); int rc = merkle_sync_init(inst, 0x31, &g_member_ops, inst); if (rc != 0) return rc; + _rebuild_all_trees(inst); DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: initialized, merkle_rc=%d", MS_ID, rc); return 0; } diff --git a/tools/chatgui/transport/merkle_sync.c b/tools/chatgui/transport/merkle_sync.c index 9812afb8..dfa9de1b 100644 --- a/tools/chatgui/transport/merkle_sync.c +++ b/tools/chatgui/transport/merkle_sync.c @@ -173,22 +173,25 @@ static int _get_level_hashes(struct merkle_sync* ms, const char* ns, next_shift = 63 - ((int)level + 1) * 5; if (next_shift < 0) next_shift = 0; } - uint64_t range_end = (level == 0) ? UINT64_MAX - : prefix | (0x1FULL << (next_shift > 0 ? next_shift : 0)); - sqlite3_stmt* stmt = NULL; int query_level = (int)(level + 1); - if (sqlite3_prepare_v2(db, - "SELECT prefix64, hash FROM merkle_tree_hash" - " WHERE namespace=? AND level=? AND prefix64>=? AND prefix64<=?" - " ORDER BY prefix64", -1, &stmt, NULL) != SQLITE_OK || !stmt) { + const char* sql = (level == 0) + ? "SELECT prefix64, hash FROM merkle_tree_hash" + " WHERE namespace=? AND level=? ORDER BY prefix64" + : "SELECT prefix64, hash FROM merkle_tree_hash" + " WHERE namespace=? AND level=? AND prefix64>=? AND prefix64<=?" + " ORDER BY prefix64"; + if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK || !stmt) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: _get_level_hashes SQL error ns=%s L%d — %s", MS_ID, ns, level, sqlite3_errmsg(db)); return -1; } sqlite3_bind_text(stmt, 1, ns, -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 2, query_level); - sqlite3_bind_int64(stmt, 3, (sqlite3_int64)prefix); - sqlite3_bind_int64(stmt, 4, (sqlite3_int64)range_end); + if (level > 0) { + uint64_t range_end = prefix | (0x1FULL << (next_shift > 0 ? next_shift : 0)); + sqlite3_bind_int64(stmt, 3, (sqlite3_int64)prefix); + sqlite3_bind_int64(stmt, 4, (sqlite3_int64)range_end); + } while (sqlite3_step(stmt) == SQLITE_ROW) { sqlite3_int64 row_pfx = sqlite3_column_int64(stmt, 0); const void* h = sqlite3_column_blob(stmt, 1);