Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,61 @@ public enum DashModelContainer {
]
}


/// The V1/V2/V3 model set: frozen copies for every model in the
/// relationship component (see `DashSchemaFrozenModels.swift`), live
/// types for the eleven models outside it, and `assetLock` for the one
/// model whose shape differs between V2 and V3.
///
/// Positionally identical to `allModelTypes` — a released version's
/// list must describe exactly the entities that version shipped.
private static func componentFrozenModelTypes(
assetLock: any PersistentModel.Type
) -> [any PersistentModel.Type] {
[
DashSchemaV1.PersistentIdentity.self,
DashSchemaV1.PersistentDPNSName.self,
DashSchemaV1.PersistentDashpayProfile.self,
DashSchemaV1.PersistentDashpayContactProfile.self,
DashSchemaV1.PersistentDashpayContactRequest.self,
DashSchemaV1.PersistentDashpayPayment.self,
DashSchemaV1.PersistentDashpayIgnoredSender.self,
DashSchemaV1.PersistentDocument.self,
DashSchemaV1.PersistentDataContract.self,
DashSchemaV1.PersistentPublicKey.self,
DashSchemaV1.PersistentTokenBalance.self,
DashSchemaV1.PersistentKeyword.self,
DashSchemaV1.PersistentToken.self,
DashSchemaV1.PersistentDocumentType.self,
DashSchemaV1.PersistentIndex.self,
DashSchemaV1.PersistentProperty.self,
DashSchemaV1.PersistentTokenHistoryEvent.self,
DashSchemaV1.PersistentPlatformAddress.self,
PersistentPlatformAddressesSyncState.self,
DashSchemaV1.PersistentWallet.self,
DashSchemaV1.PersistentAccount.self,
DashSchemaV1.PersistentCoreAddress.self,
DashSchemaV1.PersistentTransaction.self,
DashSchemaV1.PersistentTxo.self,
DashSchemaV1.PersistentPendingInput.self,
PersistentWalletManagerMetadata.self,
PersistentShieldedNote.self,
PersistentShieldedOutgoingNote.self,
PersistentShieldedSyncState.self,
PersistentShieldedActivity.self,
PersistentShieldedViewingKey.self,
assetLock,
PersistentInvitation.self,
PersistentMasternode.self
]
}

/// The exact model set registered as schema V1. Keep frozen: staged
/// migration identifies an existing store by this schema's checksum, so
/// this list may only reference models whose shape is frozen (see
/// `DashSchemaFrozenModels.swift`).
fileprivate static var v1ModelTypes: [any PersistentModel.Type] {
allModelTypes(assetLock: DashSchemaV1.PersistentAssetLock.self)
componentFrozenModelTypes(assetLock: DashSchemaV1.PersistentAssetLock.self)
}

/// The exact model set registered as schema V2 — V1 plus
Expand All @@ -66,17 +115,25 @@ public enum DashModelContainer {
v1ModelTypes + [PersistentTrackedMasternode.self]
}

/// All persistent model types in the current Dash SDK schema (V3).
/// Unlike `v1ModelTypes` / `v2ModelTypes` this list tracks the LIVE
/// models, so it moves whenever a model gains a property — which is
/// exactly why the released versions above must not.
/// The exact model set registered as schema V3 — V2's frozen component
/// with the LIVE `PersistentAssetLock`, which is the only model V3
/// changed. Frozen for the same reason as `v1ModelTypes`.
fileprivate static var v3ModelTypes: [any PersistentModel.Type] {
componentFrozenModelTypes(assetLock: PersistentAssetLock.self)
+ [PersistentTrackedMasternode.self]
}

/// All persistent model types in the current Dash SDK schema (V4).
/// Unlike the lists above this one tracks the LIVE models, so it moves
/// whenever a model gains a property — which is exactly why the
/// released versions must not.
public static var modelTypes: [any PersistentModel.Type] {
allModelTypes(assetLock: PersistentAssetLock.self) + [PersistentTrackedMasternode.self]
}

/// Create the schema for all Dash Platform models
public static var schema: Schema {
Schema(versionedSchema: DashSchemaV3.self)
Schema(versionedSchema: DashSchemaV4.self)
}

/// Create a persistent model container for storing data
Expand Down Expand Up @@ -124,13 +181,14 @@ public enum DashModelContainer {
/// SwiftData migration plan for Dash Platform model updates
public enum DashMigrationPlan: SchemaMigrationPlan {
public static var schemas: [any VersionedSchema.Type] {
[DashSchemaV1.self, DashSchemaV2.self, DashSchemaV3.self]
[DashSchemaV1.self, DashSchemaV2.self, DashSchemaV3.self, DashSchemaV4.self]
}

public static var stages: [MigrationStage] {
[
.lightweight(fromVersion: DashSchemaV1.self, toVersion: DashSchemaV2.self),
.lightweight(fromVersion: DashSchemaV2.self, toVersion: DashSchemaV3.self)
.lightweight(fromVersion: DashSchemaV2.self, toVersion: DashSchemaV3.self),
.lightweight(fromVersion: DashSchemaV3.self, toVersion: DashSchemaV4.self)
]
}
}
Expand Down Expand Up @@ -251,6 +309,24 @@ public enum DashMigrationPlan: SchemaMigrationPlan {
/// migrate with a nil `documentIdBase58`, which is the documented
/// "no marketplace state tracked" signal — the next marketplace
/// sync pass fills them in.
/// - `PersistentTxo` gained the optional `supersededByTxid`, and
/// `PersistentPendingInput` gained `isSweptTombstone` (defaulted
/// `false`). Together they let a sweep's claim on an input whose
/// funding TXO hasn't arrived yet survive the loser transaction's
/// deletion — previously that claim lived only on the doomed row's
/// `PersistentPendingInput`, which cascades away with it. Both
/// additive with defaults ⇒ lightweight migration; existing rows
/// migrate as ordinary (non-tombstone, non-superseded) entries.
/// - `PersistentPendingInput` gained the optional `winnerMinedHeight`
/// (a block-context sweep tombstone's finality stamp — the winner's
/// own mined height) and `PersistentWallet` gained the optional
/// `lastAppliedChainLockHeight` (the numeric chainlock watermark
/// delivered by `on_persist_wallet_changeset_chain_lock_height_fn`,
/// stored monotonic-max). Together they drive the bounded tombstone
/// lifetime: a tombstone is collected exactly when
/// `min(chainlockHeight, syncedHeight)` reaches its stamp. Both
/// optional ⇒ lightweight migration; pre-existing rows read as
/// unstamped (held forever) over a wallet with no boundary yet.
/// Each of those is a destructive change to a unique-attribute
/// column or to relationship topology, so any pre-existing dev
/// store will fail to open and get rebuilt from scratch on next
Expand Down Expand Up @@ -296,6 +372,27 @@ public enum DashSchemaV3: VersionedSchema {
Schema.Version(3, 0, 0)
}

public static var models: [any PersistentModel.Type] {
DashModelContainer.v3ModelTypes
}
}

/// Version 4 adds the sweep columns: `isGloballySwept` on
/// `PersistentTransaction`, `supersededByTxid` on `PersistentTxo`,
/// `isSweptTombstone` / `winnerMinedHeight` on `PersistentPendingInput`,
/// and `lastAppliedChainLockHeight` on `PersistentWallet`. Every one is
/// additive with a default or optional, so a lightweight migration
/// preserves each existing row: transactions read as not swept, TXOs as
/// unsuperseded, pending inputs as ordinary unstamped claims, and a wallet
/// as having no chainlock boundary yet.
///
/// Registering it required freezing the whole relationship component those
/// four models sit in — see `DashSchemaFrozenModels.swift`.
public enum DashSchemaV4: VersionedSchema {
public static var versionIdentifier: Schema.Version {
Schema.Version(4, 0, 0)
}

public static var models: [any PersistentModel.Type] {
DashModelContainer.modelTypes
}
Expand Down
Loading
Loading