Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7add260
feat(swift-sdk): add core wallet balance diagnostics
llbartekll Sep 1, 2026
2ed8c1d
fix(swift-sdk): keep deep core diagnostics off startup
llbartekll Sep 4, 2026
345134c
fix(swift-sdk): address diagnostics review
llbartekll Sep 4, 2026
33a7f2b
fix(swift-sdk): address core wallet diagnostics review
llbartekll Sep 7, 2026
e27c024
fix(swift-sdk): scope the migration fallback to the store's version, …
llbartekll Sep 7, 2026
9d75b93
fix(swift-sdk): lower the exact-audit transaction ceiling to 10k
llbartekll Sep 7, 2026
8fc2003
fix(swift-sdk): refuse the migration fallback for newer stores, and r…
llbartekll Sep 7, 2026
81fc3bf
fix(swift-sdk): bound the migration fallback to the entities known to…
llbartekll Sep 7, 2026
fa4b6a7
fix(swift-sdk): pin the drifted entities by hash, not by name
llbartekll Sep 7, 2026
7fd84c0
feat(swift-sdk): surface a refused newer-build store as a typed error
llbartekll Sep 7, 2026
668a707
fix(swift-sdk): drain both halves of the export, snapshot committed s…
llbartekll Sep 7, 2026
d86a763
fix(swift-sdk): never claim drift from a comparison that did not happen
llbartekll Sep 8, 2026
abde130
fix(swift-sdk): only claim "newer build" where the evidence has a dir…
llbartekll Sep 8, 2026
4d0533e
Merge branch 'v4.2-dev' into codex/cj-balance-diagnostics-sdk
llbartekll Sep 8, 2026
c0469ac
fix(swift-sdk): drain only what this manager can finish
llbartekll Sep 8, 2026
2eb5437
Merge remote-tracking branch 'origin/codex/cj-balance-diagnostics-sdk…
llbartekll Sep 8, 2026
d0cddbc
test(swift-sdk): stop pinning the drift reason to the whole entity list
llbartekll Sep 8, 2026
3e64599
Merge remote-tracking branch 'origin/v4.2-dev' into codex/cj-balance-…
llbartekll Sep 8, 2026
5cbb732
fix(swift-sdk): drop the "newer build" claim entirely — nothing here …
llbartekll Sep 8, 2026
c686477
fix(swift-sdk): judge each address pool only where accounts should ha…
llbartekll Sep 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/swift-sdk/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ let package = Package(
.testTarget(
name: "SwiftDashSDKTests",
dependencies: ["SwiftDashSDK"],
path: "SwiftTests/SwiftDashSDKTests"
path: "SwiftTests/SwiftDashSDKTests",
resources: [.copy("Fixtures")]
),

// Integration tests against a local dashmate devnet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,87 @@ import SwiftData

/// Factory for creating SwiftData model containers for Dash Platform persistence
public enum DashModelContainer {
private struct StoreFileSizes {
let main: UInt64
let wal: UInt64
let shm: UInt64

var total: UInt64 {
Comment thread
llbartekll marked this conversation as resolved.
[main, wal, shm].reduce(0) { partial, value in
let (sum, overflow) = partial.addingReportingOverflow(value)
return overflow ? UInt64.max : sum
}
}
}

/// Builds the common payload for both sides of the container open. The
/// outcome deliberately describes only what SwiftData tells us: opening an
/// existing store may have included a migration, but this API does not
/// expose whether one actually ran.
private static func storeOpenFields(
succeeded: Bool,
existedBefore: Bool,
startedAt: CFAbsoluteTime,
sizeBefore: StoreFileSizes,
sizeAfter: StoreFileSizes
) -> [String: SDKLogValue] {
let elapsed = max(0, (CFAbsoluteTimeGetCurrent() - startedAt) * 1_000)
let duration: UInt64
if !elapsed.isFinite {
duration = 0
} else if elapsed >= Double(UInt64.max) {
duration = UInt64.max
} else {
duration = UInt64(elapsed)
}
let openOutcome: String
switch (succeeded, existedBefore) {
case (true, true):
openOutcome = "existing_store_opened"
case (true, false):
openOutcome = "new_store_created"
case (false, true):
openOutcome = "existing_store_open_or_migration_failed"
case (false, false):
openOutcome = "new_store_creation_failed"
}

return [
"container_result": .publicText(succeeded ? "opened" : "open_failed"),
"container_reused": .boolean(false),
Comment thread
llbartekll marked this conversation as resolved.
Outdated
"duration_ms": .unsignedInteger(duration),
"result": .publicText(succeeded ? "success" : "failure"),
"store_existed_before_open": .boolean(existedBefore),
"store_main_size_bytes_after": .unsignedInteger(sizeAfter.main),
"store_main_size_bytes_before": .unsignedInteger(sizeBefore.main),
"store_open_outcome": .publicText(openOutcome),
"store_shm_size_bytes_after": .unsignedInteger(sizeAfter.shm),
"store_shm_size_bytes_before": .unsignedInteger(sizeBefore.shm),
"store_size_bytes_after": .unsignedInteger(sizeAfter.total),
"store_size_bytes_before": .unsignedInteger(sizeBefore.total),
"store_wal_size_bytes_after": .unsignedInteger(sizeAfter.wal),
"store_wal_size_bytes_before": .unsignedInteger(sizeBefore.wal),
]
}

/// SQLite's durable state can be mostly in the WAL immediately after an
/// app kill, so the main file alone is not a useful corruption signal.
/// Read only sizes and never include any component of the device path.
private static func storeFileSizes(at storeURL: URL) -> StoreFileSizes {
Comment thread
llbartekll marked this conversation as resolved.
func fileSize(at url: URL) -> UInt64 {
guard let size = try? url.resourceValues(forKeys: [.fileSizeKey]).fileSize,
size >= 0
else { return 0 }
return UInt64(size)
}

return StoreFileSizes(
main: fileSize(at: storeURL),
wal: fileSize(at: URL(fileURLWithPath: storeURL.path + "-wal")),
shm: fileSize(at: URL(fileURLWithPath: storeURL.path + "-shm"))
)
}

/// Every registered schema version's model list, parameterised on the
/// one model whose shape differs between versions.
///
Expand Down Expand Up @@ -97,12 +178,49 @@ public enum DashModelContainer {
)

// Always wire the migration plan so stores created by an older SDK
// advance through the registered versioned schemas.
return try ModelContainer(
for: schema,
migrationPlan: DashMigrationPlan.self,
configurations: [modelConfiguration]
)
// advance through the registered versioned schemas. Record only
// metadata about the store — never its device path.
let storeURL = modelConfiguration.url
let existedBefore = FileManager.default.fileExists(atPath: storeURL.path)
let sizeBefore = storeFileSizes(at: storeURL)
let started = CFAbsoluteTimeGetCurrent()
do {
let container = try ModelContainer(
for: schema,
migrationPlan: DashMigrationPlan.self,
configurations: [modelConfiguration]
)
let sizeAfter = storeFileSizes(at: storeURL)
SDKLogger.event(
Comment thread
llbartekll marked this conversation as resolved.
"core_store_open_result",
category: .persistence,
fields: storeOpenFields(
succeeded: true,
existedBefore: existedBefore,
startedAt: started,
sizeBefore: sizeBefore,
sizeAfter: sizeAfter
)
)
return container
} catch {
let sizeAfter = storeFileSizes(at: storeURL)
SDKLogger.event(
"core_store_open_result",
category: .persistence,
severity: .error,
fields: storeOpenFields(
succeeded: false,
existedBefore: existedBefore,
startedAt: started,
sizeBefore: sizeBefore,
sizeAfter: sizeAfter
),
error: error,
redacting: [storeURL.path]
)
throw error
}
}

/// Create an in-memory model container for testing
Expand Down
Loading
Loading