1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Use async storage instead of localstorage (#9919)

This commit is contained in:
David Walsh 2020-11-24 09:38:04 -06:00 committed by GitHub
parent 9f6fa64d67
commit bf65c979d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 187 additions and 179 deletions

View File

@ -131,6 +131,7 @@
"json-rpc-engine": "^5.3.0",
"json-rpc-middleware-stream": "^2.1.1",
"jsonschema": "^1.2.4",
"localforage": "^1.9.0",
"lodash": "^4.17.19",
"loglevel": "^1.4.1",
"luxon": "^1.24.1",

View File

@ -2,10 +2,10 @@ import assert from 'assert'
import sinon from 'sinon'
import proxyquire from 'proxyquire'
const fakeLocalStorage = {}
const fakeStorage = {}
const GasDuck = proxyquire('./gas.duck.js', {
'../../../lib/local-storage-helpers': fakeLocalStorage,
'../../../lib/storage-helpers': fakeStorage,
})
const {
@ -160,8 +160,8 @@ describe('Gas Duck', function () {
tempFetch = window.fetch
tempDateNow = global.Date.now
fakeLocalStorage.loadLocalStorageData = sinon.stub()
fakeLocalStorage.saveLocalStorageData = sinon.spy()
fakeStorage.getStorageItem = sinon.stub()
fakeStorage.setStorageItem = sinon.spy()
window.fetch = sinon.stub().callsFake(fakeFetch)
global.Date.now = () => 2000000
})
@ -412,14 +412,12 @@ describe('Gas Duck', function () {
])
})
it('should fetch recently retrieved estimates from local storage', async function () {
it('should fetch recently retrieved estimates from storage', async function () {
const mockDistpatch = sinon.spy()
fakeLocalStorage.loadLocalStorageData
fakeStorage.getStorageItem
.withArgs('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED')
.returns(2000000 - 1) // one second ago from "now"
fakeLocalStorage.loadLocalStorageData
.withArgs('BASIC_PRICE_ESTIMATES')
.returns({
fakeStorage.getStorageItem.withArgs('BASIC_PRICE_ESTIMATES').returns({
average: 25,
blockTime: 'mockBlock_time',
blockNum: 'mockBlockNum',
@ -453,9 +451,9 @@ describe('Gas Duck', function () {
])
})
it('should fallback to network if retrieving estimates from local storage fails', async function () {
it('should fallback to network if retrieving estimates from storage fails', async function () {
const mockDistpatch = sinon.spy()
fakeLocalStorage.loadLocalStorageData
fakeStorage.getStorageItem
.withArgs('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED')
.returns(2000000 - 1) // one second ago from "now"
@ -541,12 +539,12 @@ describe('Gas Duck', function () {
])
})
it('should fetch recently retrieved estimates from local storage', async function () {
it('should fetch recently retrieved estimates from storage', async function () {
const mockDistpatch = sinon.spy()
fakeLocalStorage.loadLocalStorageData
fakeStorage.getStorageItem
.withArgs('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED')
.returns(2000000 - 1) // one second ago from "now"
fakeLocalStorage.loadLocalStorageData
fakeStorage.getStorageItem
.withArgs('BASIC_GAS_AND_TIME_API_ESTIMATES')
.returns({
average: 5,
@ -596,9 +594,9 @@ describe('Gas Duck', function () {
])
})
it('should fallback to network if retrieving estimates from local storage fails', async function () {
it('should fallback to network if retrieving estimates from storage fails', async function () {
const mockDistpatch = sinon.spy()
fakeLocalStorage.loadLocalStorageData
fakeStorage.getStorageItem
.withArgs('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED')
.returns(2000000 - 1) // one second ago from "now"

View File

@ -1,9 +1,7 @@
import { uniqBy, cloneDeep, flatten } from 'lodash'
import BigNumber from 'bignumber.js'
import {
loadLocalStorageData,
saveLocalStorageData,
} from '../../../lib/local-storage-helpers'
import { getStorageItem, setStorageItem } from '../../../lib/storage-helpers'
import { decGWEIToHexWEI } from '../../helpers/utils/conversions.util'
import { isEthereumNetwork } from '../../selectors'
@ -209,7 +207,7 @@ export function fetchBasicGasEstimates() {
const { basicPriceEstimatesLastRetrieved } = getState().gas
const timeLastRetrieved =
basicPriceEstimatesLastRetrieved ||
loadLocalStorageData('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED') ||
(await getStorageItem('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED')) ||
0
dispatch(basicGasEstimatesLoadingStarted())
@ -218,7 +216,7 @@ export function fetchBasicGasEstimates() {
if (Date.now() - timeLastRetrieved > 75000) {
basicEstimates = await fetchExternalBasicGasEstimates(dispatch)
} else {
const cachedBasicEstimates = loadLocalStorageData('BASIC_PRICE_ESTIMATES')
const cachedBasicEstimates = await getStorageItem('BASIC_PRICE_ESTIMATES')
basicEstimates =
cachedBasicEstimates || (await fetchExternalBasicGasEstimates(dispatch))
}
@ -259,8 +257,10 @@ async function fetchExternalBasicGasEstimates(dispatch) {
}
const timeRetrieved = Date.now()
saveLocalStorageData(basicEstimates, 'BASIC_PRICE_ESTIMATES')
saveLocalStorageData(timeRetrieved, 'BASIC_PRICE_ESTIMATES_LAST_RETRIEVED')
await Promise.all([
setStorageItem('BASIC_PRICE_ESTIMATES', basicEstimates),
setStorageItem('BASIC_PRICE_ESTIMATES_LAST_RETRIEVED', timeRetrieved),
])
dispatch(setBasicPriceEstimatesLastRetrieved(timeRetrieved))
return basicEstimates
@ -271,7 +271,9 @@ export function fetchBasicGasAndTimeEstimates() {
const { basicPriceAndTimeEstimatesLastRetrieved } = getState().gas
const timeLastRetrieved =
basicPriceAndTimeEstimatesLastRetrieved ||
loadLocalStorageData('BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED') ||
(await getStorageItem(
'BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED',
)) ||
0
dispatch(basicGasEstimatesLoadingStarted())
@ -280,7 +282,7 @@ export function fetchBasicGasAndTimeEstimates() {
if (Date.now() - timeLastRetrieved > 75000) {
basicEstimates = await fetchExternalBasicGasAndTimeEstimates(dispatch)
} else {
const cachedBasicEstimates = loadLocalStorageData(
const cachedBasicEstimates = await getStorageItem(
'BASIC_GAS_AND_TIME_API_ESTIMATES',
)
basicEstimates =
@ -332,11 +334,13 @@ async function fetchExternalBasicGasAndTimeEstimates(dispatch) {
}
const timeRetrieved = Date.now()
saveLocalStorageData(basicEstimates, 'BASIC_GAS_AND_TIME_API_ESTIMATES')
saveLocalStorageData(
timeRetrieved,
await Promise.all([
setStorageItem('BASIC_GAS_AND_TIME_API_ESTIMATES', basicEstimates),
setStorageItem(
'BASIC_GAS_AND_TIME_API_ESTIMATES_LAST_RETRIEVED',
)
timeRetrieved,
),
])
dispatch(setBasicApiEstimatesLastRetrieved(timeRetrieved))
return basicEstimates
@ -403,11 +407,11 @@ function inliersByIQR(data, prop) {
}
export function fetchGasEstimates(blockTime) {
return (dispatch, getState) => {
return async (dispatch, getState) => {
const state = getState()
if (!isEthereumNetwork(state)) {
return Promise.resolve(null)
return
}
const {
@ -416,17 +420,18 @@ export function fetchGasEstimates(blockTime) {
} = state.gas
const timeLastRetrieved =
priceAndTimeEstimatesLastRetrieved ||
loadLocalStorageData('GAS_API_ESTIMATES_LAST_RETRIEVED') ||
(await getStorageItem('GAS_API_ESTIMATES_LAST_RETRIEVED')) ||
0
dispatch(gasEstimatesLoadingStarted())
const promiseToFetch =
Date.now() - timeLastRetrieved > 75000
? queryEthGasStationPredictionTable()
.then((r) => r.json())
.then((r) => {
const estimatedPricesAndTimes = r.map(
const shouldGetFreshGasQuote = Date.now() - timeLastRetrieved > 75000
let estimates
if (shouldGetFreshGasQuote) {
const response = await queryEthGasStationPredictionTable()
const tableJson = await response.json()
const estimatedPricesAndTimes = tableJson.map(
({ expectedTime, expectedWait, gasprice }) => ({
expectedTime,
expectedWait,
@ -499,31 +504,28 @@ export function fetchGasEstimates(blockTime) {
const timeRetrieved = Date.now()
dispatch(setApiEstimatesLastRetrieved(timeRetrieved))
saveLocalStorageData(
timeRetrieved,
'GAS_API_ESTIMATES_LAST_RETRIEVED',
)
saveLocalStorageData(timeMappedToSeconds, 'GAS_API_ESTIMATES')
return timeMappedToSeconds
})
: Promise.resolve(
priceAndTimeEstimates.length
? priceAndTimeEstimates
: loadLocalStorageData('GAS_API_ESTIMATES'),
)
await Promise.all([
setStorageItem('GAS_API_ESTIMATES_LAST_RETRIEVED', timeRetrieved),
setStorageItem('GAS_API_ESTIMATES', timeMappedToSeconds),
])
estimates = timeMappedToSeconds
} else if (priceAndTimeEstimates.length) {
estimates = priceAndTimeEstimates
} else {
estimates = await getStorageItem('GAS_API_ESTIMATES')
}
return promiseToFetch.then((estimates) => {
dispatch(setPricesAndTimeEstimates(estimates))
dispatch(gasEstimatesLoadingFinished())
})
}
}
export function setCustomGasPriceForRetry(newPrice) {
return (dispatch) => {
return async (dispatch) => {
if (newPrice === '0x0') {
const { fast } = loadLocalStorageData('BASIC_PRICE_ESTIMATES')
const { fast } = await getStorageItem('BASIC_PRICE_ESTIMATES')
dispatch(setCustomGasPrice(decGWEIToHexWEI(fast)))
} else {
dispatch(setCustomGasPrice(newPrice))

View File

@ -2,10 +2,8 @@ import { createSlice } from '@reduxjs/toolkit'
import BigNumber from 'bignumber.js'
import log from 'loglevel'
import {
loadLocalStorageData,
saveLocalStorageData,
} from '../../../lib/local-storage-helpers'
import { getStorageItem, setStorageItem } from '../../../lib/storage-helpers'
import {
addToken,
addUnapprovedTransaction,
@ -754,7 +752,7 @@ export function fetchMetaSwapsGasPriceEstimates() {
)
const timeLastRetrieved =
priceEstimatesLastRetrieved ||
loadLocalStorageData('METASWAP_GAS_PRICE_ESTIMATES_LAST_RETRIEVED') ||
(await getStorageItem('METASWAP_GAS_PRICE_ESTIMATES_LAST_RETRIEVED')) ||
0
dispatch(swapGasPriceEstimatesFetchStarted())
@ -764,7 +762,7 @@ export function fetchMetaSwapsGasPriceEstimates() {
if (Date.now() - timeLastRetrieved > 30000) {
priceEstimates = await fetchSwapsGasPrices()
} else {
const cachedPriceEstimates = loadLocalStorageData(
const cachedPriceEstimates = await getStorageItem(
'METASWAP_GAS_PRICE_ESTIMATES',
)
priceEstimates = cachedPriceEstimates || (await fetchSwapsGasPrices())
@ -795,11 +793,13 @@ export function fetchMetaSwapsGasPriceEstimates() {
const timeRetrieved = Date.now()
saveLocalStorageData(priceEstimates, 'METASWAP_GAS_PRICE_ESTIMATES')
saveLocalStorageData(
timeRetrieved,
await Promise.all([
setStorageItem('METASWAP_GAS_PRICE_ESTIMATES', priceEstimates),
setStorageItem(
'METASWAP_GAS_PRICE_ESTIMATES_LAST_RETRIEVED',
)
timeRetrieved,
),
])
dispatch(
swapGasPriceEstimatesFetchCompleted({

View File

@ -1,7 +1,4 @@
import {
loadLocalStorageData,
saveLocalStorageData,
} from '../../../lib/local-storage-helpers'
import { getStorageItem, setStorageItem } from '../../../lib/storage-helpers'
import fetchWithTimeout from '../../../../app/scripts/lib/fetch-with-timeout'
const fetchWithCache = async (
@ -27,7 +24,7 @@ const fetchWithCache = async (
}
const currentTime = Date.now()
const cachedFetch = loadLocalStorageData('cachedFetch') || {}
const cachedFetch = (await getStorageItem('cachedFetch')) || {}
const { cachedResponse, cachedTime } = cachedFetch[url] || {}
if (cachedResponse && currentTime - cachedTime < cacheRefreshTime) {
return cachedResponse
@ -52,7 +49,7 @@ const fetchWithCache = async (
cachedTime: currentTime,
}
cachedFetch[url] = cacheEntry
saveLocalStorageData(cachedFetch, 'cachedFetch')
await setStorageItem('cachedFetch', cachedFetch)
return responseJson
}

View File

@ -3,15 +3,15 @@ import nock from 'nock'
import sinon from 'sinon'
import proxyquire from 'proxyquire'
const fakeLocalStorageHelpers = {}
const fakeStorage = {}
const fetchWithCache = proxyquire('./fetch-with-cache', {
'../../../lib/local-storage-helpers': fakeLocalStorageHelpers,
'../../../lib/storage-helpers': fakeStorage,
}).default
describe('Fetch with cache', function () {
beforeEach(function () {
fakeLocalStorageHelpers.loadLocalStorageData = sinon.stub()
fakeLocalStorageHelpers.saveLocalStorageData = sinon.stub()
fakeStorage.getStorageItem = sinon.stub()
fakeStorage.setStorageItem = sinon.stub()
})
afterEach(function () {
sinon.restore()
@ -36,7 +36,7 @@ describe('Fetch with cache', function () {
.get('/price')
.reply(200, '{"average": 2}')
fakeLocalStorageHelpers.loadLocalStorageData.returns({
fakeStorage.getStorageItem.returns({
'https://fetchwithcache.metamask.io/price': {
cachedResponse: { average: 1 },
cachedTime: Date.now(),
@ -56,7 +56,7 @@ describe('Fetch with cache', function () {
.get('/price')
.reply(200, '{"average": 3}')
fakeLocalStorageHelpers.loadLocalStorageData.returns({
fakeStorage.getStorageItem.returns({
'https://fetchwithcache.metamask.io/cached': {
cachedResponse: { average: 1 },
cachedTime: Date.now() - 1000,

View File

@ -38,7 +38,7 @@ export function useRetryTransaction(transactionGroup) {
await dispatch(fetchGasEstimates(basicEstimates.blockTime))
const transaction = initialTransaction
const increasedGasPrice = increaseLastGasPrice(gasPrice)
dispatch(
await dispatch(
setCustomGasPriceForRetry(
increasedGasPrice || transaction.txParams.gasPrice,
),

View File

@ -1,20 +0,0 @@
export function loadLocalStorageData(itemKey) {
try {
const serializedData = window.localStorage.getItem(itemKey)
if (serializedData === null) {
return undefined
}
return JSON.parse(serializedData)
} catch (err) {
return undefined
}
}
export function saveLocalStorageData(data, itemKey) {
try {
const serializedData = JSON.stringify(data)
window.localStorage.setItem(itemKey, serializedData)
} catch (err) {
console.warn(err)
}
}

23
ui/lib/storage-helpers.js Normal file
View File

@ -0,0 +1,23 @@
import localforage from 'localforage'
export async function getStorageItem(key) {
try {
const serializedData = await localforage.getItem(key)
if (serializedData === null) {
return undefined
}
return JSON.parse(serializedData)
} catch (err) {
return undefined
}
}
export async function setStorageItem(key, value) {
try {
const serializedData = JSON.stringify(value)
await localforage.setItem(key, serializedData)
} catch (err) {
console.warn(err)
}
}

View File

@ -16608,6 +16608,13 @@ localforage@1.8.1:
dependencies:
lie "3.1.1"
localforage@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1"
integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g==
dependencies:
lie "3.1.1"
localstorage-down@^0.6.7:
version "0.6.7"
resolved "https://registry.yarnpkg.com/localstorage-down/-/localstorage-down-0.6.7.tgz#d0799a93b31e6c5fa5188ec06242eb1cce9d6d15"