Skip to content

Commit

Permalink
move migrations to separate files, use TS (#1482)
Browse files Browse the repository at this point in the history
  • Loading branch information
mholtzman committed Jun 23, 2023
1 parent 1cd70f8 commit 6f0ed1b
Show file tree
Hide file tree
Showing 13 changed files with 327 additions and 49 deletions.
12 changes: 12 additions & 0 deletions @types/frame/state.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
type State = {
main: {
_version: number
networks: {
ethereum: Record<number, Network>
}
networksMeta: {
ethereum: Record<number, NetworkMetadata>
}
}
}

interface Connection {
on: boolean
connected: boolean
Expand Down
38 changes: 38 additions & 0 deletions main/store/migrate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import log from 'electron-log'

import legacyMigrations from './migrations/legacy'
import migration35 from './migrations/35'
import migration36 from './migrations/36'

import type { Migration } from './types'

const migrations: Record<number, Migration> = {
...legacyMigrations,
...Object.fromEntries([
[35, migration35],
[36, migration36]
])
}

// Version number of latest known migration
const latest = Math.max(...Object.keys(migrations).map((n) => parseInt(n)))

module.exports = {
// Apply migrations to current state
apply: (state: State, migrateToVersion = latest) => {
state.main._version = state.main._version || 0
Object.keys(migrations)
.sort((a, b) => parseInt(a) - parseInt(b))
.forEach((v) => {
const version = parseInt(v)
if (state.main._version < version && version <= migrateToVersion) {
log.info(`Applying state migration: ${version}`)
state = migrations[version](state)
state.main._version = version
}
})

return state
},
latest
}
43 changes: 43 additions & 0 deletions main/store/migrate/migrations/35.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
function removeRpcConnection(connection: Connection, replaceWithPylon = true) {
const isServiceRpc = connection.current === 'infura' || connection.current === 'alchemy'

return {
...connection,
// turn off existing connections to Infura or Alchemy if they're not being replaced by Pylon
on: connection.on && (!isServiceRpc || replaceWithPylon),
current: isServiceRpc ? (replaceWithPylon ? 'pylon' : 'custom') : connection.current
}
}

function updateChain(chain: Network, replaceWithPylon = true) {
const { primary, secondary } = chain.connection

const updatedChain = {
...chain,
connection: {
...chain.connection,
primary: removeRpcConnection(primary, replaceWithPylon),
secondary: removeRpcConnection(secondary, replaceWithPylon)
}
}

return updatedChain
}

export default function (initial: State) {
const chains = Object.entries(initial.main.networks.ethereum)

// migrate existing Infura and Alchemy connections to use Pylon where applicable
const pylonChains = chains
.filter(([id]) => ['1', '5', '10', '137', '42161', '11155111'].includes(id))
.map(([id, chain]) => [id, updateChain(chain)])

// these connections previously used Infura and Alchemy and are not supported by Pylon
const retiredChains = chains
.filter(([id]) => ['3', '4', '42'].includes(id))
.map(([id, chain]) => [id, updateChain(chain, false)])

initial.main.networks.ethereum = Object.fromEntries([...chains, ...pylonChains, ...retiredChains])

return initial
}
26 changes: 26 additions & 0 deletions main/store/migrate/migrations/36.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export default function (initial: State) {
// remove Gnosis chain preset
const removePoaConnection = (connection: Connection) => {
const isPoa = connection.current === 'poa'

return {
...connection,
current: isPoa ? 'custom' : connection.current,
custom: isPoa ? 'https://rpc.gnosischain.com' : connection.custom
}
}

const gnosis = initial.main.networks.ethereum[100]

if (gnosis) {
initial.main.networks.ethereum[100] = {
...gnosis,
connection: {
primary: removePoaConnection(gnosis.connection.primary),
secondary: removePoaConnection(gnosis.connection.secondary)
}
}
}

return initial
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import log from 'electron-log'
// legacy migrations that were written in JS and have not been ported
// to Typescript

import { v5 as uuidv5 } from 'uuid'
import { z } from 'zod'

import { accountNS, isDefaultAccountName } from '../../../resources/domain/account'
import { isWindows } from '../../../resources/platform'

const migrations = {
export default {
4: (initial) => {
// If persisted state still has main.gasPrice, move gas settings into networks
const gasPrice = initial.main.gasPrice // ('gasPrice', false)
Expand Down Expand Up @@ -977,25 +979,3 @@ const migrations = {
return initial
}
}

// Version number of latest known migration
const latest = Math.max(...Object.keys(migrations))

module.exports = {
// Apply migrations to current state
apply: (state, migrateToVersion = latest) => {
state.main._version = state.main._version || 0
Object.keys(migrations)
.sort((a, b) => a - b)
.forEach((version) => {
if (parseInt(state.main._version) < version && version <= migrateToVersion) {
log.info(`Applying state migration: ${version}`)
state = migrations[version](state)
state.main._version = version
}
})

return state
},
latest
}
1 change: 1 addition & 0 deletions main/store/migrate/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type Migration = (initialState: State) => State
2 changes: 1 addition & 1 deletion main/store/persist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const path = require('path')
const electron = require('electron')
const Conf = require('conf')

const migrations = require('../migrations')
const migrations = require('../migrate')

class PersistStore extends Conf {
constructor(options) {
Expand Down
2 changes: 1 addition & 1 deletion main/store/state/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { v4: generateUuid, v5: uuidv5 } = require('uuid')

const persist = require('../persist')
const migrations = require('../migrations')
const migrations = require('../migrate')

const latestStateVersion = () => {
const state = persist.get('main')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import log from 'electron-log'

import migrations from '../../../../main/store/migrations'
import migrations from '../../../../main/store/migrate'
import { getDefaultAccountName } from '../../../../resources/domain/account'
import { capitalize } from '../../../../resources/utils'
import { isWindows } from '../../../../resources/platform'
import { createState, initChainState } from './setup'

jest.mock('../../../../resources/platform')

Expand All @@ -17,22 +18,8 @@ afterAll(() => {
log.transports.console.level = 'debug'
})

const createChainState = (chainId) => {
state.main.networks.ethereum[chainId] = { id: chainId }
state.main.networksMeta.ethereum[chainId] = { nativeCurrency: {} }
}

beforeEach(() => {
state = {
main: {
_version: 0,
networks: { ethereum: {} },
networksMeta: { ethereum: {} },
accounts: {},
balances: {},
tokens: { known: {} }
}
}
state = createState()
})

describe('migration 13', () => {
Expand Down Expand Up @@ -1385,22 +1372,22 @@ describe('migration 34', () => {

Object.entries(expectedData).forEach(([chainId, { chainName, currencyName, currencySymbol }]) => {
it(`should set the native currency name for ${chainName} to ${currencyName} if currently undefined`, () => {
createChainState(chainId)
initChainState(state, chainId)

const updatedState = migrations.apply(state, 34)
expect(getNativeCurrency(updatedState, chainId).name).toBe(currencyName)
})

it(`should set the native currency name for ${chainName} to ${currencyName} if currently an empty string'`, () => {
createChainState(chainId)
initChainState(state, chainId)
state.main.networksMeta.ethereum[chainId].nativeCurrency.name = ''

const updatedState = migrations.apply(state, 34)
expect(getNativeCurrency(updatedState, chainId).name).toBe(currencyName)
})

it(`should set the native currency symbol for ${chainName} to ${currencySymbol} if currently not set`, () => {
createChainState(chainId)
initChainState(state, chainId)

const updatedState = migrations.apply(state, 34)
expect(getNativeCurrency(updatedState, chainId).symbol).toBe(currencySymbol)
Expand All @@ -1411,15 +1398,15 @@ describe('migration 34', () => {

fields.forEach((field) => {
it(`should not overwrite an existing native currency ${field}`, () => {
createChainState(10)
initChainState(state, 10)
state.main.networksMeta.ethereum[10].nativeCurrency[field] = 'CUSTOM'

const updatedState = migrations.apply(state, 34)
expect(getNativeCurrency(updatedState, 10)[field]).toBe('CUSTOM')
})

it(`should set a missing custom chain native currency ${field} to an empty string`, () => {
createChainState(56)
initChainState(state, 56)

const updatedState = migrations.apply(state, 34)
expect(getNativeCurrency(updatedState, 56)[field]).toBe('')
Expand All @@ -1434,7 +1421,7 @@ describe('migration 34', () => {
})

it('should set native currency data when none previously existed', () => {
createChainState(137)
initChainState(state, 137)
delete state.main.networksMeta.ethereum[137].nativeCurrency

const updatedState = migrations.apply(state, 34)
Expand Down
Loading

0 comments on commit 6f0ed1b

Please sign in to comment.