Skip to content

Commit

Permalink
hotfix: Migrate remaining chrysalis profiles (#7555)
Browse files Browse the repository at this point in the history
* fix: error WIP

* fix: Attempt

* fix: Attempt 2

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* fix: Fixes

* clean up

* fmt and lint

* clean up

* clean up

* clean up

* tweak

* fix: corrupted profiles

* fix: persistedProfileMigrationToV11

* feat: Fixed `no chrysalis data to migrate` (#7565)

* fix: Fixed 'migration failed no chrysalis data to migrate'

* update comment

* tweak

* feat: add missing onSuccess

* fix: success condition

---------

Co-authored-by: Begoña Alvarez <[email protected]>

* feat: rename old profile folder names from name to id

* fix: add full profile path

---------

Co-authored-by: cpl121 <[email protected]>
Co-authored-by: Begoña Alvarez <[email protected]>
  • Loading branch information
3 people authored Oct 9, 2023
1 parent 194ee93 commit a150caf
Show file tree
Hide file tree
Showing 10 changed files with 112 additions and 31 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/build-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,24 +140,24 @@ jobs:
if: matrix.os == 'ubuntu-20.04'

- name: Sign AppImage (Linux)
run: echo $GPG_PASSPHRASE | gpg --pinentry-mode loopback --batch --passphrase-fd 0 --armor --detach-sign --default-key [email protected] firefly-desktop*.AppImage
run: echo $GPG_PASSPHRASE | gpg --pinentry-mode loopback --batch --passphrase-fd 0 --armor --detach-sign --default-key [email protected] firefly-*.AppImage
working-directory: packages/desktop/out
env:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
if: matrix.os == 'ubuntu-20.04'

- name: Compute checksums (Linux)
run: for i in `ls | grep 'firefly-desktop*'` ; do sha256sum $i | awk {'print $1'} > $i.sha256 ; done
run: for i in `ls | grep 'firefly-*'` ; do sha256sum $i | awk {'print $1'} > $i.sha256 ; done
working-directory: packages/desktop/out
if: matrix.os == 'ubuntu-20.04'

- name: Compute checksums (macOS)
run: for i in `ls | grep 'firefly-desktop*'` ; do shasum -a 256 $i | awk {'print $1'} > $i.sha256 ; done
run: for i in `ls | grep 'firefly-*'` ; do shasum -a 256 $i | awk {'print $1'} > $i.sha256 ; done
working-directory: packages/desktop/out
if: matrix.os == 'macos-11'

- name: Compute checksums (Windows)
run: Get-ChildItem "." -Filter firefly-desktop* | Foreach-Object { $(Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash | Set-Content ($_.FullName + '.sha256') }
run: Get-ChildItem "." -Filter firefly-* | Foreach-Object { $(Get-FileHash -Path $_.FullName -Algorithm SHA256).Hash | Set-Content ($_.FullName + '.sha256') }
working-directory: packages/desktop/out
if: matrix.os == 'windows-2019'

Expand All @@ -166,5 +166,5 @@ jobs:
with:
name: firefly-desktop-${{ matrix.os }}
path: |
packages/desktop/out/firefly-desktop*
packages/desktop/out/shimmer*
packages/desktop/out/firefly-*
packages/desktop/out/latest*
12 changes: 11 additions & 1 deletion packages/desktop/App.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
<script lang="ts">
import { onDestroy, onMount } from 'svelte'
import { _, isLocaleLoaded, Locale, localeDirection, setupI18n } from '@core/i18n'
import { activeProfile, checkAndMigrateProfiles, cleanupEmptyProfiles, saveActiveProfile } from '@core/profile'
import {
activeProfile,
checkAndMigrateProfiles,
cleanupEmptyProfiles,
renameOldProfileFoldersToId,
saveActiveProfile,
} from '@core/profile'
import {
AppRoute,
appRoute,
Expand Down Expand Up @@ -82,6 +88,10 @@
onMount(async () => {
features.analytics.appStart.enabled && Platform.trackEvent('app-start')
// needed for profiles that come from very old firefly chrysalis
await renameOldProfileFoldersToId()
await cleanupEmptyProfiles()
checkAndMigrateProfiles()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@ import { StrongholdVersion } from '@core/stronghold/enums'

import { getStorageDirectoryOfProfile } from '../../utils'
import { activeProfile, updateActiveProfile } from '../../stores'
import { IError } from '@core/error'

export async function migrateStrongholdFromActiveProfile(password: string): Promise<void> {
const profile = get(activeProfile)
const profileDirectory = await getStorageDirectoryOfProfile(profile?.id)
const secretManagerPath = getSecretManagerPath(profileDirectory)

if (!profile.strongholdVersion || profile.strongholdVersion === StrongholdVersion.V2) {
await api.migrateStrongholdSnapshotV2ToV3(secretManagerPath, password, secretManagerPath, password)
try {
await api.migrateStrongholdSnapshotV2ToV3(secretManagerPath, password, secretManagerPath, password)
} catch (err) {
const message = (err as IError)?.message ?? ''
if (!message.includes('input snapshot has incorrect/unexpected version')) {
throw err
}
}
updateActiveProfile({ strongholdVersion: StrongholdVersion.V3 })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MarketCurrency } from '@core/market'
import { NetworkId, getDefaultClientOptions, getDefaultPersistedNetwork } from '@core/network'
import { INode } from '@core/network/interfaces'
import { ChrysalisNetworkId } from '@core/profile/enums'
import { StrongholdVersion } from '@core/stronghold'
import { get } from 'svelte/store'
import { DEFAULT_PERSISTED_PROFILE_OBJECT } from '../../constants'
import { IChrysalisNode, IChrysalisPersistedProfile, IPersistedProfile } from '../../interfaces'
Expand Down Expand Up @@ -32,8 +33,7 @@ export function checkAndMigrateChrysalisProfiles(): boolean {
hasVisitedDashboard: chrysalisProfile.hasVisitedDashboard ?? undefined,
clientOptions: DEFAULT_PERSISTED_PROFILE_OBJECT.clientOptions, // migration needed
forceAssetRefresh: DEFAULT_PERSISTED_PROFILE_OBJECT.forceAssetRefresh,
strongholdVersion:
chrysalisProfile.strongholdVersion ?? DEFAULT_PERSISTED_PROFILE_OBJECT.strongholdVersion,
strongholdVersion: chrysalisProfile.strongholdVersion ?? StrongholdVersion.V2,
needsChrysalisToStardustDbMigration: true,
}

Expand Down Expand Up @@ -114,7 +114,7 @@ function getMigratedNetworkId(chrysalisNetworkId: ChrysalisNetworkId): NetworkId
case ChrysalisNetworkId.PrivateNet:
return NetworkId.Custom
default:
throw new Error(`Unable to migrate network: ${chrysalisNetworkId}`)
return NetworkId.Iota
}
}

Expand Down Expand Up @@ -152,11 +152,18 @@ function isChrysalisProfile(profile: IPersistedProfile | IChrysalisPersistedProf
if (chrysalisProfileNetworkId) {
return chrysalisNetworkIdsArray.includes(chrysalisProfileNetworkId)
}
const hasChrysalisNode = (chrysalisProfile.settings?.networkConfig?.nodes?.length || 0) > 0 || false
return hasChrysalisNode
} else if ('accounts' in profile && !('accountPersistedData' in profile)) {
const chrysalisProfileAccounts = chrysalisProfile?.accounts ?? []
if (chrysalisProfileAccounts.find((account) => account.id.startsWith('wallet-account://'))) {
return true
}
} else {
const partiallyStardustProfile = profile as IPersistedProfile
if (!partiallyStardustProfile.network || !partiallyStardustProfile.accountPersistedData) {
return true
}
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
IIscpChainMetadata,
NetworkId,
} from '@core/network'
import { DEFAULT_NETWORK_METADATA } from '../../../../core/network/constants/default-network-metadata.constant'
import { NetworkMetadata } from '../../../../core/network/types/network-metadata.type'
import { INode, IPersistedNetwork } from '@core/network/interfaces'
import { DEFAULT_MAX_NFT_DOWNLOADING_TIME_IN_SECONDS, DEFAULT_MAX_NFT_SIZE_IN_MEGABYTES } from '@core/nfts'
import { ProfileType } from '@core/profile/enums'
Expand All @@ -29,13 +31,11 @@ import { checkAndMigrateChrysalisProfiles } from './'
export function checkAndMigrateProfiles(): void {
const _currentProfileVersion = get(currentProfileVersion)
const CHRYSALIS_TO_STARDUST_PROFILE_VERSION = 13
if (_currentProfileVersion === -1) currentProfileVersion.set(CHRYSALIS_TO_STARDUST_PROFILE_VERSION)
const shouldMigratePersistedProfiles = (_currentProfileVersion ?? 3) < PROFILE_VERSION

// patch chrysalis unmigrated profiles
if (
shouldMigratePersistedProfiles ||
(_currentProfileVersion >= CHRYSALIS_TO_STARDUST_PROFILE_VERSION && _currentProfileVersion <= 16)
) {
// patch chrysalis unmigrated profiles to re-check profiles until v16
if (shouldMigratePersistedProfiles || _currentProfileVersion <= 16) {
if (checkAndMigrateChrysalisProfiles()) {
// If there was a migration, we need to update the currentProfileVersion
// to the latest compatible with the chrysalis migration, which is 13
Expand Down Expand Up @@ -161,7 +161,7 @@ function persistedProfileMigrationToV8(existingProfile: IPersistedProfile): void
}

function persistedProfileMigrationToV9(existingProfile: IPersistedProfile): void {
function migrateNode(node: INode): INode {
function migrateNode(node: INode | undefined): INode {
if (node) {
return {
url: node.url as string,
Expand All @@ -177,6 +177,10 @@ function persistedProfileMigrationToV9(existingProfile: IPersistedProfile): void
}
}

if (!existingProfile.clientOptions) {
existingProfile.clientOptions = {}
}

existingProfile.clientOptions.nodes = existingProfile?.clientOptions?.nodes?.map(migrateNode)
existingProfile.clientOptions.primaryNode = migrateNode(existingProfile?.clientOptions?.primaryNode)

Expand Down Expand Up @@ -215,10 +219,13 @@ function persistedProfileMigrationToV11(
const networkId = getNetworkIdFromOldNetworkType(existingProfile?.networkType)
if (networkId === NetworkId.Shimmer || networkId === NetworkId.Testnet) {
network = getDefaultPersistedNetwork(networkId)
network.coinType = COIN_TYPE[NetworkId.Shimmer]
} else {
network.id = NetworkId.Custom
network = {
chains: [],
...(DEFAULT_NETWORK_METADATA[NetworkId.Iota] as NetworkMetadata),
}
}
network.coinType = COIN_TYPE[NetworkId.Shimmer]
existingProfile.network = structuredClone(network)
}

Expand Down Expand Up @@ -324,6 +331,12 @@ function persistedProfileMigrationToV15(existingProfile: IPersistedProfile): voi
}

function persistedProfileMigrationToV16(existingProfile: IPersistedProfile): void {
if (!existingProfile.network) {
existingProfile.network = {
chains: [],
...(DEFAULT_NETWORK_METADATA[NetworkId.Iota] as NetworkMetadata),
}
}
const defaultChainConfig = DEFAULT_CHAIN_CONFIGURATIONS[existingProfile.network.id]
const newChains: IIscpChainMetadata[] = defaultChainConfig ? [defaultChainConfig] : []
existingProfile.network.chains = newChains
Expand Down
1 change: 1 addition & 0 deletions packages/shared/lib/core/profile/actions/profiles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export * from './checkAndMigrateChrysalisProfiles'
export * from './migrateDbChrysalisToStardust'
export * from './checkAndMigrateProfiles'
export * from './cleanupEmptyProfiles'
export * from './renameOldProfileFoldersToId'
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { api } from '@core/profile-manager'
import { updateProfile } from '@core/profile/stores'
import { getStorageDirectoryOfProfile } from '@core/profile/utils'

const ATTEMPT_MIGRATION_CHRYSALIS_TO_STARUDST_ERROR = 'migration failed no chrysalis data to migrate'

/**
* Updates the profile underlying DB from chrysalis model to stardust.
* @param profileId The profile that needs migration.
Expand All @@ -13,25 +15,39 @@ export async function migrateDbChrysalisToStardust(profileId: string, pinCode: s
const profileDirectory = await getStorageDirectoryOfProfile(profileId)
const response = await api.migrateDbChrysalisToStardust(profileDirectory, pinCode)

const _onSuccess = (): void => {
updateProfile(profileId, { needsChrysalisToStardustDbMigration: undefined })
}

if (response instanceof Error) {
updateProfile(profileId, { needsChrysalisToStardustDbMigration: true })
let reason = ''
let success = false

try {
reason = JSON.parse(response.message).payload?.error

// The 'no chrysalis data to migrate' error only happens when entering a Stardust profile
// that the wallet got migrated (hence the error) but the profile didn't, we can safely skip this error.
if (reason === ATTEMPT_MIGRATION_CHRYSALIS_TO_STARUDST_ERROR) {
success = true
}
} finally {
logAndNotifyError({
type: 'wallet',
message: `Chrysalis database migration failed: ${reason}`,
saveToErrorLog: true,
showNotification: true,
originalError: response,
})
if (success) {
_onSuccess()
} else {
logAndNotifyError({
type: 'wallet',
message: `Chrysalis database migration failed: ${reason}`,
saveToErrorLog: true,
showNotification: true,
originalError: response,
})
}
}

return false
return success
} else {
updateProfile(profileId, { needsChrysalisToStardustDbMigration: undefined })
_onSuccess()
return true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Platform } from '@core/app'
import { profiles } from '@core/profile/stores'
import { getStorageDirectoryOfProfile, getStorageDirectoryOfProfiles } from '@core/profile/utils'
import { get } from 'svelte/store'

export async function renameOldProfileFoldersToId(): Promise<void> {
const walletPath = await getStorageDirectoryOfProfiles()
const profileFolders = await Platform.listProfileFolders(walletPath)
const oldProfiles = get(profiles).filter((profile) =>
profileFolders.find((p) => p === profile.name && profile.name !== profile.id)
)
if (oldProfiles.length > 0) {
await Promise.all(
oldProfiles.map(async (profile) => {
await renameProfileFolder(profile.name, profile.id)
})
)
}
}

async function renameProfileFolder(oldName: string, newName: string): Promise<void> {
const oldPath = await getStorageDirectoryOfProfile(oldName)
const newPath = await getStorageDirectoryOfProfile(newName)
await Platform.renameProfileFolder(oldPath, newPath)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ProfileType } from '../enums'
import { IPersistedProfile } from '../interfaces'
import { DEFAULT_STRONGHOLD_PASSWORD_TIMEOUT_IN_MINUTES } from './default_stronghold_password_timeout_in_minutes.constant'
import { DEFAULT_MAX_NFT_DOWNLOADING_TIME_IN_SECONDS, DEFAULT_MAX_NFT_SIZE_IN_MEGABYTES } from '@core/nfts/constants'
import { StrongholdVersion } from '../../../core/stronghold/enums/stronghold-version.enum'

export const DEFAULT_PERSISTED_PROFILE_OBJECT: IPersistedProfile = {
id: '',
Expand All @@ -21,6 +22,6 @@ export const DEFAULT_PERSISTED_PROFILE_OBJECT: IPersistedProfile = {
accountPersistedData: {},
isDeveloperProfile: false,
forceAssetRefresh: false,
strongholdVersion: undefined,
strongholdVersion: StrongholdVersion.V3,
clientOptions: {},
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { persistent } from '@core/utils/store'

export const currentProfileVersion = persistent<number>('currentProfileVersion', -1)
export const currentProfileVersion = persistent<number>('currentProfileVersion', 13)

0 comments on commit a150caf

Please sign in to comment.