Version signed node snapshots with persistent timestamps

This commit is contained in:
evgeny committed 2026-09-27 19:11:11 +03:00
1 parent 7374d1648c
commit ec51b2d61f
10 files changed
+440 -95

No files matched your search

+62
View File
@@ -253,6 +253,8 @@ int topo_node_sqlite_init(sqlite3* db) {
if (!db) return -1;
const char* sql =
"CREATE TABLE IF NOT EXISTS node_snapshots ("
"node_id INTEGER PRIMARY KEY, timestamp INTEGER NOT NULL, record BLOB NOT NULL);"
"CREATE TABLE IF NOT EXISTS nodes ("
" node_id INTEGER PRIMARY KEY,"
" name TEXT,"
@@ -903,8 +905,68 @@ void topo_node_sqlite_update_rtt(sqlite3* db, uint64_t node_id, uint16_t rtt) {
(unsigned long long)node_id, (unsigned)rtt);
}
uint64_t topo_node_sqlite_snapshot_timestamp(sqlite3* db, uint64_t node_id) {
sqlite3_stmt* stmt = NULL;
uint64_t timestamp = 0;
if (sqlite3_prepare_v2(db, "SELECT timestamp FROM node_snapshots WHERE node_id=?", -1, &stmt, NULL) != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "snapshot timestamp: %s", sqlite3_errmsg(db)); return 0;
}
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
int rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) timestamp = (uint64_t)sqlite3_column_int64(stmt, 0);
else if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_BGP, "snapshot timestamp read: %s", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
return timestamp;
}
int topo_node_sqlite_snapshot_put(sqlite3* db, struct TOPO_NODE* ni) {
if (!db || topo_node_verify(ni) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid node snapshot"); return -1; }
uint8_t record[4096];
struct TOPO_GROUP_NODE nq = {0};
int len = topo_node_serialize(ni, &nq, 0, 0, record, sizeof(record), 0);
if (len < 0) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "snapshot serialization failed"); return -1; }
sqlite3_stmt* stmt = NULL;
const char* sql = "INSERT INTO node_snapshots(node_id,timestamp,record) VALUES(?,?,?) "
"ON CONFLICT(node_id) DO UPDATE SET timestamp=excluded.timestamp,record=excluded.record "
"WHERE excluded.timestamp > node_snapshots.timestamp";
int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)ni->node_id);
sqlite3_bind_int64(stmt, 2, (sqlite3_int64)ni->timestamp);
sqlite3_bind_blob(stmt, 3, record, len, SQLITE_STATIC);
rc = sqlite3_step(stmt);
}
if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_BGP, "snapshot write: %s", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
return rc == SQLITE_DONE ? 0 : -1;
}
struct TOPO_NODE* topo_node_sqlite_snapshot_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id) {
sqlite3_stmt* stmt = NULL;
struct TOPO_NODE* ni = NULL;
if (sqlite3_prepare_v2(db, "SELECT record FROM node_snapshots WHERE node_id=?", -1, &stmt, NULL) != SQLITE_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "snapshot load: %s", sqlite3_errmsg(db)); return NULL;
}
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
int rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
struct TOPO_GROUP group = { .instance = groups->instance };
const uint8_t* data = sqlite3_column_blob(stmt, 0);
int len = sqlite3_column_bytes(stmt, 0);
if (topo_node_deserialize(&group, data, (size_t)len, &ni, NULL, NULL, NULL, NULL) < 0 ||
!ni || ni->node_id != node_id || topo_node_verify(ni) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid persisted snapshot node=%016llx", (unsigned long long)node_id);
topo_node_destroy(groups, ni); ni = NULL;
}
} else if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_BGP, "snapshot read: %s", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
return ni;
}
struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id) {
if (!db || !groups) return NULL;
struct TOPO_NODE* snapshot = topo_node_sqlite_snapshot_load(db, groups, node_id);
if (snapshot) return snapshot;
uint8_t pubkey[32] = {0}, ed_pubkey[32] = {0};
char* name = NULL;