Merge pull request #3786 from Sjors: Track seen relays from successful OKs
Track seen relays from successful OKs
This commit is contained in:
@@ -430,6 +430,7 @@
|
|||||||
4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DEF727F7A08200C66700 /* damusTests.swift */; };
|
4CE6DEF827F7A08200C66700 /* damusTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DEF727F7A08200C66700 /* damusTests.swift */; };
|
||||||
4CE6DF0227F7A08200C66700 /* damusUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0127F7A08200C66700 /* damusUITests.swift */; };
|
4CE6DF0227F7A08200C66700 /* damusUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF0127F7A08200C66700 /* damusUITests.swift */; };
|
||||||
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */; };
|
4CE6DF1627F8DEBF00C66700 /* RelayConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE6DF1527F8DEBF00C66700 /* RelayConnection.swift */; };
|
||||||
|
D72A1A022F73B9F800B0010B /* RelayPoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72A1A012F73B9F800B0010B /* RelayPoolTests.swift */; };
|
||||||
4CE8794829941DA700F758CC /* RelayFilters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE8794729941DA700F758CC /* RelayFilters.swift */; };
|
4CE8794829941DA700F758CC /* RelayFilters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE8794729941DA700F758CC /* RelayFilters.swift */; };
|
||||||
4CE8794E2996B16A00F758CC /* RelayToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE8794D2996B16A00F758CC /* RelayToggle.swift */; };
|
4CE8794E2996B16A00F758CC /* RelayToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE8794D2996B16A00F758CC /* RelayToggle.swift */; };
|
||||||
4CE879502996B2BD00F758CC /* RelayStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE8794F2996B2BD00F758CC /* RelayStatusView.swift */; };
|
4CE879502996B2BD00F758CC /* RelayStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CE8794F2996B2BD00F758CC /* RelayStatusView.swift */; };
|
||||||
@@ -2838,6 +2839,7 @@
|
|||||||
D72734272F08912F00F90677 /* DatabaseSnapshotManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseSnapshotManagerTests.swift; sourceTree = "<group>"; };
|
D72734272F08912F00F90677 /* DatabaseSnapshotManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseSnapshotManagerTests.swift; sourceTree = "<group>"; };
|
||||||
D72734292F089EE600F90677 /* NdbMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NdbMigrationTests.swift; sourceTree = "<group>"; };
|
D72734292F089EE600F90677 /* NdbMigrationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NdbMigrationTests.swift; sourceTree = "<group>"; };
|
||||||
D72927AC2BAB515C00F93E90 /* RelayURLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayURLTests.swift; sourceTree = "<group>"; };
|
D72927AC2BAB515C00F93E90 /* RelayURLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayURLTests.swift; sourceTree = "<group>"; };
|
||||||
|
D72A1A012F73B9F800B0010B /* RelayPoolTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayPoolTests.swift; sourceTree = "<group>"; };
|
||||||
D72A2CFF2AD9B66B002AFF62 /* EventViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventViewTests.swift; sourceTree = "<group>"; };
|
D72A2CFF2AD9B66B002AFF62 /* EventViewTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventViewTests.swift; sourceTree = "<group>"; };
|
||||||
D72A2D042AD9C1B5002AFF62 /* MockDamusState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDamusState.swift; sourceTree = "<group>"; };
|
D72A2D042AD9C1B5002AFF62 /* MockDamusState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDamusState.swift; sourceTree = "<group>"; };
|
||||||
D72A2D062AD9C1FB002AFF62 /* MockProfiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProfiles.swift; sourceTree = "<group>"; };
|
D72A2D062AD9C1FB002AFF62 /* MockProfiles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockProfiles.swift; sourceTree = "<group>"; };
|
||||||
@@ -4005,6 +4007,7 @@
|
|||||||
E0E024102B7C19C20075735D /* TranslationTests.swift */,
|
E0E024102B7C19C20075735D /* TranslationTests.swift */,
|
||||||
E06336A92B75832100A88E6B /* ImageMetadataTest.swift */,
|
E06336A92B75832100A88E6B /* ImageMetadataTest.swift */,
|
||||||
D7CBD1D52B8D509800BFD889 /* DamusPurpleImpendingExpirationTests.swift */,
|
D7CBD1D52B8D509800BFD889 /* DamusPurpleImpendingExpirationTests.swift */,
|
||||||
|
D72A1A012F73B9F800B0010B /* RelayPoolTests.swift */,
|
||||||
D72927AC2BAB515C00F93E90 /* RelayURLTests.swift */,
|
D72927AC2BAB515C00F93E90 /* RelayURLTests.swift */,
|
||||||
D753CEA92BE9DE04001C3A5D /* MutingTests.swift */,
|
D753CEA92BE9DE04001C3A5D /* MutingTests.swift */,
|
||||||
4C2D34402BDAF1B300F9FB44 /* NIP10Tests.swift */,
|
4C2D34402BDAF1B300F9FB44 /* NIP10Tests.swift */,
|
||||||
@@ -6518,6 +6521,7 @@
|
|||||||
D72A2D052AD9C1B5002AFF62 /* MockDamusState.swift in Sources */,
|
D72A2D052AD9C1B5002AFF62 /* MockDamusState.swift in Sources */,
|
||||||
E06336AA2B75832100A88E6B /* ImageMetadataTest.swift in Sources */,
|
E06336AA2B75832100A88E6B /* ImageMetadataTest.swift in Sources */,
|
||||||
D77A96BF2F3131BE00CC3246 /* RelayHintsTests.swift in Sources */,
|
D77A96BF2F3131BE00CC3246 /* RelayHintsTests.swift in Sources */,
|
||||||
|
D72A1A022F73B9F800B0010B /* RelayPoolTests.swift in Sources */,
|
||||||
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */,
|
4C363AA02828A8DD006E126D /* LikeTests.swift in Sources */,
|
||||||
D7A0D8752D1FE67900DCBE59 /* EditPictureControlTests.swift in Sources */,
|
D7A0D8752D1FE67900DCBE59 /* EditPictureControlTests.swift in Sources */,
|
||||||
D776BE442F23301A002DA1C9 /* EntityPreloaderTests.swift in Sources */,
|
D776BE442F23301A002DA1C9 /* EntityPreloaderTests.swift in Sources */,
|
||||||
|
|||||||
@@ -734,15 +734,23 @@ class RelayPool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Records that a relay is known to have accepted or returned a note.
|
||||||
|
func record_seen(relay_id: RelayURL, note_id: NoteId) {
|
||||||
|
if seen[note_id]?.contains(relay_id) == true {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
seen[note_id, default: Set()].insert(relay_id)
|
||||||
|
counts[relay_id, default: 0] += 1
|
||||||
|
notify(.update_stats(note_id: note_id))
|
||||||
|
}
|
||||||
|
|
||||||
func record_seen(relay_id: RelayURL, event: NostrConnectionEvent) {
|
func record_seen(relay_id: RelayURL, event: NostrConnectionEvent) {
|
||||||
if case .nostr_event(let ev) = event {
|
if case .nostr_event(let ev) = event {
|
||||||
if case .event(_, let nev) = ev {
|
if case .event(_, let nev) = ev {
|
||||||
if seen[nev.id]?.contains(relay_id) == true {
|
record_seen(relay_id: relay_id, note_id: nev.id)
|
||||||
return
|
} else if case .ok(let result) = ev, result.ok {
|
||||||
}
|
record_seen(relay_id: relay_id, note_id: result.event_id)
|
||||||
seen[nev.id, default: Set()].insert(relay_id)
|
|
||||||
counts[relay_id, default: 0] += 1
|
|
||||||
notify(.update_stats(note_id: nev.id))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,45 +18,105 @@ final class RelayPoolTests: XCTestCase {
|
|||||||
override func tearDownWithError() throws {
|
override func tearDownWithError() throws {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAddRelay_ValidRelayURL_NoErrors() {
|
@MainActor
|
||||||
testAddRelays(urls: [
|
func testAddRelay_ValidRelayURL_NoErrors() async {
|
||||||
|
await testAddRelays(urls: [
|
||||||
"wss://relay.damus.io"
|
"wss://relay.damus.io"
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAddRelay_TwoSameURLs_ThrowsRelayAlreadyExists() {
|
@MainActor
|
||||||
testAddRelays(urls: [
|
func testAddRelay_TwoSameURLs_ThrowsRelayAlreadyExists() async {
|
||||||
|
await testAddRelays(urls: [
|
||||||
"wss://relay.damus.io",
|
"wss://relay.damus.io",
|
||||||
"wss://relay.damus.io"
|
"wss://relay.damus.io"
|
||||||
], expectedError: .RelayAlreadyExists)
|
], expectedError: .RelayAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAddRelay_OneExtraneousSlashURL_ThrowsRelayAlreadyExists() {
|
@MainActor
|
||||||
testAddRelays(urls: [
|
func testAddRelay_OneExtraneousSlashURL_ThrowsRelayAlreadyExists() async {
|
||||||
|
await testAddRelays(urls: [
|
||||||
"wss://relay.damus.io",
|
"wss://relay.damus.io",
|
||||||
"wss://relay.damus.io/"
|
"wss://relay.damus.io/"
|
||||||
], expectedError: .RelayAlreadyExists)
|
], expectedError: .RelayAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAddRelay_MultipleExtraneousSlashURL_ThrowsRelayAlreadyExists() {
|
@MainActor
|
||||||
testAddRelays(urls: [
|
func testAddRelay_MultipleExtraneousSlashURL_ThrowsRelayAlreadyExists() async {
|
||||||
|
await testAddRelays(urls: [
|
||||||
"wss://relay.damus.io",
|
"wss://relay.damus.io",
|
||||||
"wss://relay.damus.io///"
|
"wss://relay.damus.io///"
|
||||||
], expectedError: .RelayAlreadyExists)
|
], expectedError: .RelayAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAddRelay_ExtraSlashURLFirst_ThrowsRelayAlreadyExists() {
|
@MainActor
|
||||||
testAddRelays(urls: [
|
func testAddRelay_ExtraSlashURLFirst_ThrowsRelayAlreadyExists() async {
|
||||||
|
await testAddRelays(urls: [
|
||||||
"wss://relay.damus.io///",
|
"wss://relay.damus.io///",
|
||||||
"wss://relay.damus.io"
|
"wss://relay.damus.io"
|
||||||
], expectedError: .RelayAlreadyExists)
|
], expectedError: .RelayAlreadyExists)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates fresh inputs for seen-recording tests.
|
||||||
|
func makeRecordSeenFixture() throws -> (pool: RelayPool, relay: RelayURL, noteID: NoteId) {
|
||||||
|
let relay = try XCTUnwrap(RelayURL("wss://relay.example.com"))
|
||||||
|
let noteID = try XCTUnwrap(NoteId(hex: String(repeating: "a", count: 64)))
|
||||||
|
return (RelayPool(ndb: nil), relay, noteID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAddRelays(urls: [String], expectedError: RelayError? = nil) {
|
/// Verifies successful relay OK responses update the relay provenance map.
|
||||||
let ndb = Ndb()!
|
func testRecordSeenRecordsSuccessfulOKResponses() async throws {
|
||||||
let relayPool = RelayPool(ndb: ndb)
|
let (pool, relay, noteID) = try makeRecordSeenFixture()
|
||||||
let info = RelayInfo(read: true, write: true)
|
let result = CommandResult(event_id: noteID, ok: true, msg: "")
|
||||||
|
|
||||||
|
await pool.record_seen(relay_id: relay, event: .nostr_event(.ok(result)))
|
||||||
|
|
||||||
|
let seenRelays = await pool.seen[noteID]
|
||||||
|
let relayCount = await pool.counts[relay]
|
||||||
|
|
||||||
|
XCTAssertEqual(seenRelays, Set([relay]))
|
||||||
|
XCTAssertEqual(relayCount, Optional(UInt64(1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies duplicate relay OK responses do not increment provenance twice.
|
||||||
|
func testRecordSeenRecordsDuplicateSuccessfulOKResponsesOnce() async throws {
|
||||||
|
let (pool, relay, noteID) = try makeRecordSeenFixture()
|
||||||
|
let acceptedResult = CommandResult(event_id: noteID, ok: true, msg: "")
|
||||||
|
let duplicateResult = CommandResult(
|
||||||
|
event_id: noteID,
|
||||||
|
ok: true,
|
||||||
|
msg: "duplicate: already have this event"
|
||||||
|
)
|
||||||
|
|
||||||
|
await pool.record_seen(relay_id: relay, event: .nostr_event(.ok(acceptedResult)))
|
||||||
|
await pool.record_seen(relay_id: relay, event: .nostr_event(.ok(duplicateResult)))
|
||||||
|
|
||||||
|
let seenRelays = await pool.seen[noteID]
|
||||||
|
let relayCount = await pool.counts[relay]
|
||||||
|
|
||||||
|
XCTAssertEqual(seenRelays, Set([relay]))
|
||||||
|
XCTAssertEqual(relayCount, Optional(UInt64(1)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies failed relay OK responses do not count as relay provenance.
|
||||||
|
func testRecordSeenIgnoresFailedOKResponses() async throws {
|
||||||
|
let (pool, relay, noteID) = try makeRecordSeenFixture()
|
||||||
|
let result = CommandResult(event_id: noteID, ok: false, msg: "blocked: test")
|
||||||
|
|
||||||
|
await pool.record_seen(relay_id: relay, event: .nostr_event(.ok(result)))
|
||||||
|
|
||||||
|
let seenRelays = await pool.seen[noteID]
|
||||||
|
let relayCount = await pool.counts[relay]
|
||||||
|
|
||||||
|
XCTAssertNil(seenRelays)
|
||||||
|
XCTAssertNil(relayCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds relay URLs to a pool and verifies duplicate URL handling.
|
||||||
|
@MainActor
|
||||||
|
func testAddRelays(urls: [String], expectedError: RelayPool.RelayError? = nil) async {
|
||||||
|
let relayPool = RelayPool(ndb: nil)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for relay in urls {
|
for relay in urls {
|
||||||
@@ -65,18 +125,16 @@ func testAddRelays(urls: [String], expectedError: RelayError? = nil) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let descriptor = RelayDescriptor(url: url, info: info)
|
let descriptor = RelayPool.RelayDescriptor(url: url, info: .readWrite)
|
||||||
try relayPool.add_relay(descriptor)
|
try await relayPool.add_relay(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
if expectedError != nil {
|
if expectedError != nil {
|
||||||
XCTFail("Expected \(expectedError!) error, but no error was thrown.")
|
XCTFail("Expected \(expectedError!) error, but no error was thrown.")
|
||||||
}
|
}
|
||||||
} catch let error as RelayError where expectedError == .RelayAlreadyExists {
|
} catch let error as RelayPool.RelayError where expectedError == .RelayAlreadyExists {
|
||||||
XCTAssertEqual(error, expectedError!, "Expected RelayAlreadyExists error, got \(error)")
|
XCTAssertEqual(error, expectedError!, "Expected RelayAlreadyExists error, got \(error)")
|
||||||
} catch {
|
} catch {
|
||||||
XCTFail("An unexpected error was thrown: \(error)")
|
XCTFail("An unexpected error was thrown: \(error)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user