Redesign Ndb.swift interface with build safety

This commit redesigns the Ndb.swift interface with a focus on build-time
safety against crashes.

It removes the external usage of NdbTxn and SafeNdbTxn, restricting it
to be used only in NostrDB internal code.

This prevents dangerous and crash prone usages throughout the app, such
as holding transactions in a variable in an async function (which can
cause thread-based reference counting to incorrectly deinit inherited
transactions in use by separate callers), as well as holding unsafe
unowned values longer than the lifetime of their corresponding
transactions.

Closes: https://github.com/damus-io/damus/issues/3364
Changelog-Fixed: Fixed several crashes throughout the app
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
Daniel D’Aquino
2025-11-28 19:17:35 -08:00
parent b562b930cc
commit f844ed9931
60 changed files with 611 additions and 497 deletions

View File

@@ -137,11 +137,9 @@ class NostrNetworkManagerTests: XCTestCase {
switch item {
case .event(let noteKey):
// Lookup the note to verify it exists
if let txn = NdbTxn(ndb: ndb) {
if let note = ndb.lookup_note_by_key_with_txn(noteKey, txn: txn) {
count += 1
receivedIds.insert(note.id)
}
if let note = ndb.lookup_note_by_key_and_copy(noteKey) {
count += 1
receivedIds.insert(note.id)
}
if count >= expectedCount {
atLeastXNotes.fulfill()

View File

@@ -347,15 +347,17 @@ class NoteContentViewTests: XCTestCase {
func testDirectBlockParsing() {
let kp = test_keypair_full
let dm: NdbNote = NIP04.create_dm("Test", to_pk: kp.pubkey, tags: [], keypair: kp.to_keypair())!
let blocks = try! NdbBlockGroup.from(event: dm, using: test_damus_state.ndb, and: kp.to_keypair())
let blockCount1 = try? blocks.withList({ $0.count })
XCTAssertEqual(blockCount1, 1)
try! NdbBlockGroup.borrowBlockGroup(event: dm, using: test_damus_state.ndb, and: kp.to_keypair(), borrow: { blocks in
let blockCount = blocks.withList({ $0.count })
XCTAssertEqual(blockCount, 1)
})
let post = NostrPost(content: "Test", kind: .text)
let event = post.to_event(keypair: kp)!
let blocks2 = try! NdbBlockGroup.from(event: event, using: test_damus_state.ndb, and: kp.to_keypair())
let blockCount2 = try? blocks2.withList({ $0.count })
XCTAssertEqual(blockCount2, 1)
try! NdbBlockGroup.borrowBlockGroup(event: event, using: test_damus_state.ndb, and: kp.to_keypair(), borrow: { blocks in
let blockCount = blocks.withList({ $0.count })
XCTAssertEqual(blockCount, 1)
})
}
func testMentionStr_Pubkey_ContainsAbbreviated() throws {