Skip to content
Permalink
Browse files

migration checkpoint

  • Loading branch information...
SebastienGllmt committed Oct 9, 2019
1 parent 63289c9 commit 97b7fa26d4e226baa064c04aa0961fe48932f9b3
@@ -1016,9 +1016,6 @@ export default class AdaApi {
// Note: we only restore for 0th account
const accountIndex = HARD_DERIVATION_START + 0;
const rootPk = generateWalletRootKey(recoveryPhrase);
const accountKey = rootPk.bip44_account(
RustModule.Wallet.AccountIndex.new(accountIndex)
);

const wallet = await createStandardBip44Wallet({
db: request.db,
@@ -1027,7 +1024,6 @@ export default class AdaApi {
}),
rootPk,
password: walletPassword,
accountPublicKey: accountKey.public(),
accountIndex,
walletName,
accountName: '', // set account name empty now
@@ -18,16 +18,16 @@ export async function saveSelectedExplorer(explorer: ExplorerType): Promise<void
}

export async function getSelectedExplorer(): Promise<ExplorerType> {
const explorer = await _getFromStorage(storageKeys.SELECTED_EXPLORER_KEY);
const explorer = await _getFromStorage<ExplorerType>(storageKeys.SELECTED_EXPLORER_KEY);
return explorer || Explorer.SEIZA;
}

/* Util functions */
async function _saveInStorage(key: string, toSave: any): Promise<void> {
export async function _saveInStorage(key: string, toSave: any): Promise<void> {
await setLocalItem(key, JSON.stringify(toSave));
}

async function _getFromStorage(key: string): any | void {
export async function _getFromStorage<T>(key: string): Promise<T | void> {
return await getLocalItem(key).then((result) => {
if (result == null) {
return result;
@@ -6,6 +6,11 @@ import type { lf$Database } from 'lovefield';
import {
resetLegacy,
getLegacyAddressesList,
legacyGetLastReceiveAddressIndex,
legacySaveLastReceiveAddressIndex,
legacyGetLocalStorageWallet,
getCurrentCryptoAccount,
clearStorageV1,
} from './database/legacy';
import LocalStorageApi from '../../../localStorage/index';
import {
@@ -17,6 +22,12 @@ import {
import {
OPEN_TAB_ID_KEY,
} from '../../../../utils/tabManager';
import { migrateFromStorageV1 } from './bridge/walletHelper';
import { RustModule } from '../cardanoCrypto/rustLoader';
import type { ConfigType } from '../../../../../config/config-types';

declare var CONFIG: ConfigType;
const protocolMagic = CONFIG.network.protocolMagic;

export async function migrateToLatest(
localStorageApi: LocalStorageApi,
@@ -134,7 +145,7 @@ async function bip44Migration(

// if we had more than one address, then the WALLET key must exist in localstorage
try {
await saveLastReceiveAddressIndex(maxIndex);
await legacySaveLastReceiveAddressIndex(maxIndex);
} catch (_err) {
// no wallet in storage
return false;
@@ -158,8 +169,46 @@ async function storagev2Migation(
persistentDb: lf$Database,
): Promise<boolean> {
// all information in the v1 indexdb can be inferred from the blockchain
await reset(persistentDb);
await resetLegacy();

const wallet = await legacyGetLocalStorageWallet();
const account = await getCurrentCryptoAccount();
if (wallet != null && account != null) {
const lastReceiveIndex = await legacyGetLastReceiveAddressIndex();

const settings = RustModule.Wallet.BlockchainSettings.from_json({
protocol_magic: protocolMagic
});
const migratedWallet = await migrateFromStorageV1({
db: persistentDb,
accountPubKey: account.root_cached_key,
displayCutoff: lastReceiveIndex,
encryptedPk: wallet.masterKey == null
? undefined
: {
Hash: wallet.masterKey,
IsEncrypted: true,
PasswordLastUpdate: wallet.adaWallet.cwPassphraseLU == null
? null
: wallet.adaWallet.cwPassphraseLU,
},
hwWalletMetaInsert: wallet.adaWallet.cwHardwareInfo == null
? undefined
: {
Vendor: wallet.adaWallet.cwHardwareInfo.vendor,
Model: wallet.adaWallet.cwHardwareInfo.model,
Label: wallet.adaWallet.cwHardwareInfo.deviceId,
DeviceId: wallet.adaWallet.cwHardwareInfo.label,
Language: wallet.adaWallet.cwHardwareInfo.language,
MajorVersion: wallet.adaWallet.cwHardwareInfo.majorVersion,
MinorVersion: wallet.adaWallet.cwHardwareInfo.minorVersion,
PatchVersion: wallet.adaWallet.cwHardwareInfo.patchVersion,
},
settings,
walletName: wallet.adaWallet.cwMeta.cwName,
});
}

await clearStorageV1();
return true;
}
@@ -34,17 +34,11 @@ export async function setup(
const entropy = RustModule.Wallet.Entropy.from_english_mnemonics(walletMnemonic);
const rootPk = RustModule.Wallet.Bip44RootPrivateKey.recover(entropy, '');

const firstAccountIndex = 0 + HARD_DERIVATION_START;
const firstAccountPk = rootPk.bip44_account(
RustModule.Wallet.AccountIndex.new(firstAccountIndex)
);

const state = await createStandardBip44Wallet({
db,
settings,
rootPk,
password: privateDeriverPassword,
accountPublicKey: firstAccountPk.public(),
accountIndex: HARD_DERIVATION_START + 0,
walletName: 'My Test Wallet',
accountName: '',
@@ -9,6 +9,7 @@ import {
CARDANO_COINTYPE,
BIP44_PURPOSE,
BIP44_SCAN_SIZE,
EXTERNAL,
} from '../../../../../config/numbersConfig';

import type {
@@ -17,6 +18,7 @@ import type {
import {
GetOrAddAddress,
} from '../database/uncategorized/api/write';
import type { KeyInsert } from '../database/uncategorized/tables';
import type { HWFeatures, } from '../database/wallet/tables';

import { WalletBuilder } from './walletBuilder';
@@ -108,8 +110,6 @@ export async function createStandardBip44Wallet(request: {
settings: RustModule.Wallet.BlockchainSettings,
rootPk: RustModule.Wallet.Bip44RootPrivateKey,
password: string,
// TODO: remove since we know root PK and index
accountPublicKey: RustModule.Wallet.Bip44AccountPublic,
accountIndex: number,
walletName: string,
accountName: string,
@@ -123,6 +123,10 @@ export async function createStandardBip44Wallet(request: {
Buffer.from(request.rootPk.key().to_hex(), 'hex'),
);

const accountPublicKey = request.rootPk.bip44_account(
RustModule.Wallet.AccountIndex.new(request.accountIndex)
).public();

// Note: we generate initial addresses in a separate database query
// from creation of the actual wallet
const initialDerivations = await raii(
@@ -141,7 +145,7 @@ export async function createStandardBip44Wallet(request: {

return await getAccountDefaultDerivations(
request.settings,
request.accountPublicKey,
accountPublicKey,
hashToIdFunc,
);
}
@@ -299,6 +303,7 @@ export async function createHardwareWallet(request: {
Name: request.accountName,
LastSyncInfoId: ids.lastSyncInfoId,
}),
parentDerivationId: null,
pathToPublic: [
{
index: BIP44_PURPOSE,
@@ -325,3 +330,146 @@ export async function createHardwareWallet(request: {

return state;
}

export async function migrateFromStorageV1(request: {
db: lf$Database,
settings: RustModule.Wallet.BlockchainSettings,
encryptedPk: void | KeyInsert,
accountPubKey: string,
displayCutoff: number,
walletName: string,
hwWalletMetaInsert: void | HWFeatures,
}): Promise<HasConceptualWallet & HasBip44Wrapper & HasPublicDeriver<mixed>> {

const accountIndex = HARD_DERIVATION_START + 0;
const accountName = '';

const accountPublicKey = RustModule.Wallet.Bip44AccountPublic.new(
RustModule.Wallet.PublicKey.from_hex(request.accountPubKey),
RustModule.Wallet.DerivationScheme.v2()
);

// Note: we generate initial addresses in a separate database query
// from creation of the actual wallet
const initialDerivations = await raii(
request.db,
getAllSchemaTables(request.db, GetOrAddAddress),
async tx => {
const hashToIdFunc = async (
addressHash: Array<string>
): Promise<Array<number>> => {
const rows = await GetOrAddAddress.addByHash(
request.db, tx,
addressHash
);
return rows.map(row => row.AddressId);
};

const insert = await getAccountDefaultDerivations(
request.settings,
accountPublicKey,
hashToIdFunc,
);
// replace default display cutoff
const external = insert.find(chain => chain.index === EXTERNAL);
if (external == null) {
throw new Error('migrateFromStorageV1 cannot find external chain. Should never happen');
}
external.insert.DisplayCutoff = request.displayCutoff;

return insert;
}
);

let state;
{
let builder = WalletBuilder
.start(request.db)
.addConceptualWallet(
_finalState => ({
CoinType: CARDANO_COINTYPE,
Name: request.walletName,
})
)
.addBip44Wrapper(
finalState => ({
ConceptualWalletId: finalState.conceptualWalletRow.ConceptualWalletId,
IsBundled: false,
SignerLevel: DerivationLevels.ROOT.level,
PublicDeriverLevel: DerivationLevels.ACCOUNT.level,
Version: 2,
})
);
if (request.encryptedPk != null) {
const encryptedPk = request.encryptedPk;
builder = builder.addPrivateDeriver(
finalState => ({
// private deriver level === root level
pathToPrivate: [],
addLevelRequest: parent => ({
privateKeyInfo: encryptedPk,
publicKeyInfo: null,
derivationInfo: keys => ({
PublicKeyId: keys.public,
PrivateKeyId: keys.private,
Parent: parent,
Index: null,
}),
levelInfo: id => ({
KeyDerivationId: id,
})
}),
addPrivateDeriverRequest: derivationId => ({
Bip44WrapperId: finalState.bip44WrapperRow.Bip44WrapperId,
KeyDerivationId: derivationId,
Level: DerivationLevels.ROOT.level,
}),
})
);
}
builder = builder
.addAdhocPublicDeriver(
finalState => ({
bip44WrapperId: finalState.bip44WrapperRow.Bip44WrapperId,
publicKey: {
Hash: accountPublicKey.key().to_hex(),
IsEncrypted: false,
PasswordLastUpdate: null,
},
publicDeriverInsert: ids => ({
Bip44WrapperId: ids.wrapperId,
KeyDerivationId: ids.derivationId,
Name: accountName,
LastSyncInfoId: ids.lastSyncInfoId,
}),
parentDerivationId: finalState.privateDeriver == null
? null
: finalState.privateDeriver.privateDeriverResult.KeyDerivationId,
pathToPublic: [
{
index: BIP44_PURPOSE,
insert: {},
},
{
index: CARDANO_COINTYPE,
insert: {},
},
{
index: accountIndex,
insert: {},
},
],
initialDerivations,
hwWalletMetaInsert: request.hwWalletMetaInsert == null
? undefined
: {
ConceptualWalletId: finalState.conceptualWalletRow.ConceptualWalletId,
...request.hwWalletMetaInsert
},
})
);
state = builder.commit();
}

return state;
}
@@ -630,6 +630,7 @@ export class ModifyDisplayCutoff {
export type AddAdhocPublicDeriverRequest = {|
bip44WrapperId: number,
publicKey: KeyInsert,
parentDerivationId: null | number,
pathToPublic: InsertPath,
publicDeriverInsert: {
derivationId: number,
@@ -659,7 +660,7 @@ export class AddAdhocPublicDeriver {
tx: lf$Transaction,
request: AddAdhocPublicDeriverRequest,
): Promise<AddAdhocPublicDeriverResponse<Row>> {
let parentId: number | null = null;
let parentId: number | null = request.parentDerivationId;
for (let i = 0; i < request.pathToPublic.length - 1; i++) {
const levelResult = await AddPrivateDeriver.depTables.AddDerivation.add(
db, tx,
@@ -62,7 +62,7 @@ export const loadLovefieldDB = async (
const populateAndCreate = async (
storeType: $Values<typeof schema.DataStoreType>
): Promise<lf$Database> => {
const schemaBuilder = schema.create('yoroi-schema', 7);
const schemaBuilder = schema.create('yoroi-schema', 2);

populateUncategorizedDb(schemaBuilder);
populateBip44Db(schemaBuilder);

0 comments on commit 97b7fa2

Please sign in to comment.
You can’t perform that action at this time.