/* topo_node_sqlite — хранение подписанных снимков узлов, адресов, каналов и блоков мемберов в общей SQLite. * Модель/проверка подписей/registry — topo_node и member_sync; этот модуль реализует SQL-операции в uasync-потоке. * snapshot_put проверяет подпись и сохраняет только более свежий timestamp; node_load предпочитает snapshot. * db/groups заимствованы. Возвращённый TOPO_NODE без registry ref: передать registry либо уничтожить через topo_node_destroy. * Массивы out_ids/out_ch_ids/out_peers принадлежат вызывающему и освобождаются u_free. */ #ifndef TOPO_NODE_SQLITE_H #define TOPO_NODE_SQLITE_H #include #include #include #include #include "topo_node.h" #define PEERS_JOIN_SIG_SIZE 64 #define PEERS_JOIN_TS_SIZE 8 #define PEERS_UPDATE_SIG_SIZE 64 /* flags byte in wire format */ #define PEERS_FLAG_HAS_JOIN 0x01 int topo_node_sqlite_init(sqlite3* db); int topo_node_sqlite_snapshot_put(sqlite3* db, struct TOPO_NODE* ni); uint64_t topo_node_sqlite_snapshot_timestamp(sqlite3* db, uint64_t node_id); struct TOPO_NODE* topo_node_sqlite_snapshot_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id); /* Персистентная запись адресов узла в node_addresses (источник истины — BGP/topo_group). * DELETE + INSERT из ni->v4_addrs/v6_addrs; mapping/inbound/source из подписанного SOCKMETA. */ int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* ni); /* Есть ли у узла запись мембера хотя бы в одной peers_ (реальный мембер с ключами). */ int topo_node_sqlite_member_exists(sqlite3* db, uint64_t node_id); /* Список channel_id (uint64) всех peers_, где узел является членом. 0=ок. */ int topo_node_sqlite_get_member_channels(sqlite3* db, uint64_t node_id, uint64_t** out_ch_ids, int* out_count); int topo_node_sqlite_channel_put(sqlite3* db, const char* channel_id, const char* name, uint64_t owner_node_id, const uint8_t* x25519_pub, const uint8_t* x25519_priv, const uint8_t* ed25519_pub, const uint8_t* ed25519_priv, const uint8_t* signature); /* Подготовить локальные поля участника при создании и загрузке канала. */ int topo_node_sqlite_member_local_init(sqlite3* db, const char* channel_id); /* Полное локальное удаление канала: DROP peers_/msg_, DELETE channels, * Удаляются feedback_ и merkle_tree_hash всех datasets этого канала. 0=ок. */ int topo_node_sqlite_channel_delete(sqlite3* db, const char* channel_id); /* Упрощённый плейсхолдер мембера от topo_group (source=1, не участвует в merkle-хеше). */ int topo_node_sqlite_member_placeholder_put(sqlite3* db, const char* channel_id, uint64_t node_id, const uint8_t* x25519_pubkey, const uint8_t* ed25519_pubkey); /* Обновляет только блок мембера (keys/join/update_sig/update_ts/userinfo), не трогая блок владельца. * signed_by/signature — дерево приглашений: кто подписал pubkey узла (0 = корень, ключом группы). */ int topo_node_sqlite_member_block_put(sqlite3* db, const char* channel_id, uint64_t node_id, const uint8_t* join_sig, uint64_t join_ts, const uint8_t* update_sig, uint64_t update_ts, const uint8_t* x25519_pubkey, const uint8_t* ed25519_pubkey, const char* userinfo, const uint8_t* creator_sig, uint64_t signed_by, const uint8_t* signature); /* Прочитать дерево приглашений мембера (signed_by + signature). 0=ок, -1=нет записи/полей. */ int topo_node_sqlite_member_get_sign(sqlite3* db, const char* channel_id, uint64_t node_id, uint64_t* signed_by_out, uint8_t signature_out[64]); /* Есть ли узел в таблице мемберов канала peers_ (source 0 или 1). 1=да, 0=нет. */ int topo_node_sqlite_member_in_channel(sqlite3* db, const char* channel_id, uint64_t node_id); /* Обновляет только блок владельца (adm_tags/adm_tags_sig/storage). */ int topo_node_sqlite_member_owner_put(sqlite3* db, const char* channel_id, uint64_t node_id, const char* adm_tags, const uint8_t* adm_tags_sig, int storage); int topo_node_sqlite_member_get_join(sqlite3* db, const char* channel_id, uint64_t node_id, uint8_t* join_sig_out, uint64_t* join_ts_out); int topo_node_sqlite_member_del(sqlite3* db, const char* channel_id, uint64_t node_id); int topo_node_sqlite_node_update_verified(sqlite3* db, uint64_t node_id, const char* name, const uint8_t* x25519, const uint8_t* ed25519, uint64_t update_ts, time_t created_at); int topo_node_sqlite_channel_get(sqlite3* db, const char* channel_id, char* name_out, int name_sz, uint64_t* owner_node_id, uint8_t* x25519_pub, uint8_t* ed25519_pub, uint8_t* signature); int topo_node_sqlite_channel_get_priv(sqlite3* db, const char* channel_id, uint8_t* ed25519_priv_out); /* Прочитать оба канальных privkey (x25519 + ed25519). Возвращает 0 если оба есть. */ int topo_node_sqlite_channel_get_privs(sqlite3* db, const char* channel_id, uint8_t* x25519_priv_out, uint8_t* ed25519_priv_out); /* Записать оба канальных privkey (импорт прав админа). */ int topo_node_sqlite_channel_set_privs(sqlite3* db, const char* channel_id, const uint8_t* x25519_priv, const uint8_t* ed25519_priv); int topo_node_sqlite_node_set_online(sqlite3* db, uint64_t node_id, int online); int topo_node_sqlite_node_get_online(sqlite3* db, uint64_t node_id); int topo_node_sqlite_get_ed25519_pubkey(sqlite3* db, uint64_t node_id, uint8_t pubkey_out[32]); /** Пересчитывает node_type во всех peers_* таблицах на основе addr_type из node_addresses */ int topo_node_sqlite_nodeinfo_updated(sqlite3* db, uint64_t node_id); /** Обновляет RTT узла: node_addresses.rtt и все peers_*.node_RTT */ void topo_node_sqlite_update_rtt(sqlite3* db, uint64_t node_id, uint16_t rtt); /** * @brief Загружает TOPO_NODE из SQLite (ref_count=0). * @param groups нужен для выделения адресов из memory_pool * @return TOPO_NODE* или NULL если узел не найден/нет адресов * * Сначала загружает и проверяет подписанный snapshot; при его отсутствии собирает сведения nodes/node_addresses. * Вызывающий передаёт владение через topo_node_registry_acquire() либо вызывает topo_node_destroy(). */ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id); int topo_node_sqlite_set_connected(sqlite3* db, const char* channel_id, uint64_t node_id, int connected); /* Кандидат CHAT-подключения: роль канальная, тип устройства из подписанного snapshot. * UINT8_MAX означает отсутствие сведений о типе; адреса не ограничивают выборку. */ struct topo_connect_peer { uint64_t node_id; uint8_t client_type, supernode; }; /* Все неудалённые участники, включая self; сначала connected, затем RTT/node_id. * 0/-1; массив принадлежит вызывающему и освобождается u_free(). */ int topo_node_sqlite_get_connect_peers(sqlite3* db, const char* channel_id, struct topo_connect_peer** out, size_t* out_count); int topo_node_sqlite_get_connected_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count); int topo_node_sqlite_get_public_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count, uint64_t self_node_id); int topo_node_sqlite_get_local_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count, uint64_t self_node_id); int topo_node_sqlite_get_supernode_peers(sqlite3* db, const char* channel_id, uint64_t** out_ids, int* out_count); /* node_type узла в канале (peers_.node_type); -1 если нет записи/ошибка. */ int topo_node_sqlite_get_node_type(sqlite3* db, const char* channel_id, uint64_t node_id); #endif