mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-02-22 23:08:07 +01:00
REF: store HD wallets txs in realm properly, one per row (closes #3357)
This commit is contained in:
parent
cb2dfdbd86
commit
59e126de3d
2 changed files with 83 additions and 39 deletions
|
@ -228,16 +228,16 @@ export class AppStorage {
|
|||
const password = this.hashIt(this.cachedPassword || 'fyegjitkyf[eqjnc.lf');
|
||||
const buf = Buffer.from(this.hashIt(password) + this.hashIt(password), 'hex');
|
||||
const encryptionKey = Int8Array.from(buf);
|
||||
const path = this.hashIt(this.hashIt(password)) + '-wallets.realm';
|
||||
const path = this.hashIt(this.hashIt(password)) + '-wallettransactions.realm';
|
||||
|
||||
const schema = [
|
||||
{
|
||||
name: 'Wallet',
|
||||
primaryKey: 'walletid',
|
||||
name: 'WalletTransactions',
|
||||
properties: {
|
||||
walletid: { type: 'string', indexed: true },
|
||||
_txs_by_external_index: 'string', // stringified json
|
||||
_txs_by_internal_index: 'string', // stringified json
|
||||
internal: 'bool?', // true - internal, false - external
|
||||
index: 'int?',
|
||||
tx: 'string', // stringified json
|
||||
},
|
||||
},
|
||||
];
|
||||
|
@ -317,7 +317,12 @@ export class AppStorage {
|
|||
}
|
||||
}
|
||||
if (data !== null) {
|
||||
const realm = await this.getRealm();
|
||||
let realm;
|
||||
try {
|
||||
realm = await this.getRealm();
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
}
|
||||
data = JSON.parse(data);
|
||||
if (!data.wallets) return false;
|
||||
const wallets = data.wallets;
|
||||
|
@ -410,7 +415,7 @@ export class AppStorage {
|
|||
break;
|
||||
}
|
||||
|
||||
this.inflateWalletFromRealm(realm, unserializedWallet);
|
||||
if (realm) this.inflateWalletFromRealm(realm, unserializedWallet);
|
||||
|
||||
// done
|
||||
if (!this.wallets.some(wallet => wallet.getSecret() === unserializedWallet.secret)) {
|
||||
|
@ -418,7 +423,7 @@ export class AppStorage {
|
|||
this.tx_metadata = data.tx_metadata;
|
||||
}
|
||||
}
|
||||
realm.close();
|
||||
if (realm) realm.close();
|
||||
return true;
|
||||
} else {
|
||||
return false; // failed loading data or loading/decryptin data
|
||||
|
@ -450,24 +455,28 @@ export class AppStorage {
|
|||
};
|
||||
|
||||
inflateWalletFromRealm(realm, walletToInflate) {
|
||||
const wallets = realm.objects('Wallet');
|
||||
const filteredWallets = wallets.filtered(`walletid = "${walletToInflate.getID()}" LIMIT(1)`);
|
||||
for (const realmWalletData of filteredWallets) {
|
||||
try {
|
||||
if (realmWalletData._txs_by_external_index) {
|
||||
const txsByExternalIndex = JSON.parse(realmWalletData._txs_by_external_index);
|
||||
const txsByInternalIndex = JSON.parse(realmWalletData._txs_by_internal_index);
|
||||
|
||||
if (walletToInflate._hdWalletInstance) {
|
||||
walletToInflate._hdWalletInstance._txs_by_external_index = txsByExternalIndex;
|
||||
walletToInflate._hdWalletInstance._txs_by_internal_index = txsByInternalIndex;
|
||||
} else {
|
||||
walletToInflate._txs_by_external_index = txsByExternalIndex;
|
||||
walletToInflate._txs_by_internal_index = txsByInternalIndex;
|
||||
}
|
||||
const transactions = realm.objects('WalletTransactions');
|
||||
const transactionsForWallet = transactions.filtered(`walletid = "${walletToInflate.getID()}"`);
|
||||
for (const tx of transactionsForWallet) {
|
||||
if (tx.internal === false) {
|
||||
if (walletToInflate._hdWalletInstance) {
|
||||
walletToInflate._hdWalletInstance._txs_by_external_index[tx.index] =
|
||||
walletToInflate._hdWalletInstance._txs_by_external_index[tx.index] || [];
|
||||
walletToInflate._hdWalletInstance._txs_by_external_index[tx.index].push(JSON.parse(tx.tx));
|
||||
} else {
|
||||
walletToInflate._txs_by_external_index[tx.index] = walletToInflate._txs_by_external_index[tx.index] || [];
|
||||
walletToInflate._txs_by_external_index[tx.index].push(JSON.parse(tx.tx));
|
||||
}
|
||||
}
|
||||
if (tx.internal === true) {
|
||||
if (walletToInflate._hdWalletInstance) {
|
||||
walletToInflate._hdWalletInstance._txs_by_internal_index[tx.index] =
|
||||
walletToInflate._hdWalletInstance._txs_by_internal_index[tx.index] || [];
|
||||
walletToInflate._hdWalletInstance._txs_by_internal_index[tx.index].push(JSON.parse(tx.tx));
|
||||
} else {
|
||||
walletToInflate._txs_by_internal_index[tx.index] = walletToInflate._txs_by_internal_index[tx.index] || [];
|
||||
walletToInflate._txs_by_internal_index[tx.index].push(JSON.parse(tx.tx));
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,17 +487,42 @@ export class AppStorage {
|
|||
|
||||
if (walletToSave._txs_by_external_index) {
|
||||
realm.write(() => {
|
||||
const j1 = JSON.stringify(walletToSave._txs_by_external_index);
|
||||
const j2 = JSON.stringify(walletToSave._txs_by_internal_index);
|
||||
realm.create(
|
||||
'Wallet',
|
||||
{
|
||||
walletid: id,
|
||||
_txs_by_external_index: j1,
|
||||
_txs_by_internal_index: j2,
|
||||
},
|
||||
Realm.UpdateMode.Modified,
|
||||
);
|
||||
// cleanup all existing transactions for the wallet first
|
||||
const walletTransactionsToDelete = realm.objects('WalletTransactions').filtered(`walletid = '${id}'`);
|
||||
realm.delete(walletTransactionsToDelete);
|
||||
|
||||
// insert new ones:
|
||||
for (const index of Object.keys(walletToSave._txs_by_external_index)) {
|
||||
const txs = walletToSave._txs_by_external_index[index];
|
||||
for (const tx of txs) {
|
||||
realm.create(
|
||||
'WalletTransactions',
|
||||
{
|
||||
walletid: id,
|
||||
internal: false,
|
||||
index: parseInt(index),
|
||||
tx: JSON.stringify(tx),
|
||||
},
|
||||
Realm.UpdateMode.Modified,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (const index of Object.keys(walletToSave._txs_by_internal_index)) {
|
||||
const txs = walletToSave._txs_by_internal_index[index];
|
||||
for (const tx of txs) {
|
||||
realm.create(
|
||||
'WalletTransactions',
|
||||
{
|
||||
walletid: id,
|
||||
internal: true,
|
||||
index: parseInt(index),
|
||||
tx: JSON.stringify(tx),
|
||||
},
|
||||
Realm.UpdateMode.Modified,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -511,14 +545,19 @@ export class AppStorage {
|
|||
|
||||
try {
|
||||
const walletsToSave = [];
|
||||
const realm = await this.getRealm();
|
||||
let realm;
|
||||
try {
|
||||
realm = await this.getRealm();
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
}
|
||||
for (const key of this.wallets) {
|
||||
if (typeof key === 'boolean' || key.type === PlaceholderWallet.type) continue;
|
||||
key.prepareForSerialization();
|
||||
delete key.current;
|
||||
const keyCloned = Object.assign({}, key); // stripped-down version of a wallet to save to secure keystore
|
||||
if (key._hdWalletInstance) keyCloned._hdWalletInstance = Object.assign({}, key._hdWalletInstance);
|
||||
this.offloadWalletToRealm(realm, key);
|
||||
if (realm) this.offloadWalletToRealm(realm, key);
|
||||
// stripping down:
|
||||
if (key._txs_by_external_index) {
|
||||
keyCloned._txs_by_external_index = {};
|
||||
|
@ -530,7 +569,7 @@ export class AppStorage {
|
|||
}
|
||||
walletsToSave.push(JSON.stringify({ ...keyCloned, type: keyCloned.type }));
|
||||
}
|
||||
realm.close();
|
||||
if (realm) realm.close();
|
||||
let data = {
|
||||
wallets: walletsToSave,
|
||||
tx_metadata: this.tx_metadata,
|
||||
|
|
|
@ -296,3 +296,8 @@ it('can decrypt storage that is second in a list of buckets; and isPasswordInUse
|
|||
assert.ok(storage5loadResult);
|
||||
assert.strictEqual(Storage7.wallets[0].getLabel(), 'fakewallet');
|
||||
});
|
||||
|
||||
it('Appstorage - hashIt() works', async () => {
|
||||
const storage = new AppStorage();
|
||||
assert.strictEqual(storage.hashIt('hello'), '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824');
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue