From 5983acd9886caa3606cc5969096840847a66638a Mon Sep 17 00:00:00 2001 From: Evgeny Date: Sat, 25 Jul 2026 17:37:12 +0300 Subject: [PATCH] =?UTF-8?q?merkle=5Fsync:=20fix=20=5Fget=5Flevel=5Fhashes?= =?UTF-8?q?=20=E2=80=94=20range=20query=20instead=20of=20exact=20mismatch?= =?UTF-8?q?=20(prefix=20encoding=20bug)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/chatgui/transport/merkle_sync.c | 30 ++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/tools/chatgui/transport/merkle_sync.c b/tools/chatgui/transport/merkle_sync.c index 94df19d6..7dcb2267 100644 --- a/tools/chatgui/transport/merkle_sync.c +++ b/tools/chatgui/transport/merkle_sync.c @@ -165,15 +165,31 @@ static int _get_level_hashes(struct merkle_sync* ms, const char* ns, memset(hashes, 0, sizeof(uint8_t) * MT_BUCKETS * MT_HASH_SIZE); *bitmap = 0; if (level >= MT_MAX_LEVEL) return 0; - int next_shift = 63 - ((int)level + 1) * 5; - for (int i = 0; i < MT_BUCKETS; i++) { - uint64_t child_prefix = prefix | ((uint64_t)i << (next_shift > 0 ? next_shift : 0)); - const uint8_t* h = merkle_sync_get_hash(ms->inst, ns, (uint8_t)(level + 1), child_prefix); - int empty = 1; - for (int j = 0; j < MT_HASH_SIZE; j++) { if (h[j] != 0) { empty = 0; break; } } - if (!empty) { *bitmap |= (1u << i); memcpy(hashes[i], h, MT_HASH_SIZE); } + sqlite3* db = _db(ms->inst); if (!db) return -1; + int parent_shift = 63 - (int)level * 5; if (parent_shift < 0) parent_shift = 0; + int next_shift = 63 - ((int)level + 1) * 5; if (next_shift < 0) next_shift = 0; + uint64_t range_end = prefix | ((1ULL << parent_shift) - 1); + + sqlite3_stmt* stmt = NULL; + 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) + return -1; + sqlite3_bind_text(stmt, 1, ns, -1, SQLITE_STATIC); + sqlite3_bind_int(stmt, 2, (int)(level + 1)); + 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); + if (!h || sqlite3_column_bytes(stmt, 1) < MT_HASH_SIZE) continue; + int bucket = (int)(((uint64_t)row_pfx >> next_shift) & 0x1F); + *bitmap |= (1u << bucket); + memcpy(hashes[bucket], h, MT_HASH_SIZE); } + sqlite3_finalize(stmt); return 0; }