A data race was introduced in #9919 when the old synchronous storage
API was replaced with an async storage API. The problem arises when
`fetchWithCache` is called a second time while it's still processing
another call. In this case, the `cachedFetch` object can become
stale while blocked waiting for a fetch response, and result in a cache
being overwritten unintentionally.
See this example (options omitted for simplicity, and assuming an empty
initial cache):
```
await Promise.all([
fetchWithCache('https://metamask.io/foo'),
fetchWithCache('https://metamask.io/bar'),
]
```
The order of events could be as follows:
1. Empty cache retrieved for `/foo` route
2. Empty cache retrieved for `/bar` route
3. Call made to `/foo` route
4. Call made to `/bar` route
5. `/foo` response is added to the empty cache object retrieved in
step 1, then is saved in the cache.
6. `/bar` response is added to the empty cache object retrieved in
step 2, then is saved in the cache.
In step 6, the cache object saved would not contain the `/foo`
response set in step 5. As a result, `/foo` would never be cached.
This problem was resolved by embedding the URL being cached directly in
the cache key. This prevents simultaneous responses from overwriting
each others caches.
Technically a data race still exists when handing simultaneous
responses to the same route, but the result would be that the last call
to finish would overwrite the previous. This seems acceptable.
`eth_getProof` is an unpermissioned, read-only RPC method for getting account-related Merkle proofs, specified here: https://eips.ethereum.org/EIPS/eip-1186
It's been supported by major Ethereum clients, and Infura, for some time. By adding it to the safe methods list, we enable this method for our users.
* Maintain console logging in dev mode
Co-authored-by: kumavis <aaron@kumavis.me>
Co-authored-by: Erik Marks <rekmarks@protonmail.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Additional validation was added in #9907 to ensure that the "Known
contract address" warning was shown when sending tokens to another
token address after switching assets on the Send screen. Unfortunately
this change had the unintended side-effect of preventing _all_ token
sends after switching assets, so long as the recipient was not an
internal address.
The problem is that the `validate` function expects to be passed the
address of the token send recipient in the case where a token is
selected. Instead the token address was being passed to the validate
function.
The `query` state is now used, which should always contain the
recipient address. This is the same state used in the only other place
the `validate` function is called.
On Firefox 56 and Waterfox Classic, our `runLockdown.js` script throws
an error. This is fine on the HTML pages, as the next script tags still
get run without issue (though they don't benefit from the SES lockdown
sadly). But in the `contentscript`, an exception thrown here appears to
halt the execution of subsequent scripts.
To prevent the `contentscript` from crashing completely, lockdown
errors are now caught and logged. They are also logged to Sentry on the
pages where Sentry is setup.
The `eth_decrypt` used to fail on Firefox with a recursion error.
Updating these `tweetnacl` dependencies seemed to have fixed the issue
the last time I tested this.
When I tried to reproduce the failure today, it failed due to a
different reason, both before and after this update.
But nonetheless, it still seems like a good idea to update. These newer
versions have no breaking changes and contain important bug fixes.
When you load an extension `.zip` file in Firefox, it fails to load
scripts with the `.cjs` file extension. However, it works if you load
the extension via the `manifest.json` file instead.
After renaming the `lockdown.cjs` file to `lockdown.js`, it works in
Firefox in all cases, regardless whether it's loaded by manifest or by
`.zip`.
The new metrics controller has a `trackEvent` function that was being
called unbound, so `this` references were undefined. It is now bound
early in both places where it is passed in as a parameter.
The SES lockdown added in #9729 had the effect of obfuscating our error
messages. Any messages printed to the console would have the error
message replaced with the string "Error #" followed by a number. The
stack was also updated to point at `lockdown.cjs`, though the original
stack was preserved beneath the top stack frame.
Marking the `console` API as untamed seems to have fixed both issues.
The original error message is now printed to the console, along with
the original stack.
When the SES lockdown was added in #9729, the lockdown and the Sentry
initialization were migrated from the main bundle into separate
modules, which were run as separate `<script>` tags. These extra tags
were accidentally omitted for `home.html` and `notification.html`. As
a result Sentry was not initialized on these pages, so any errors
thrown on them would not be collected. They also do not benefit from
the SES lockdown.
The SES lockdown and Sentry initialization modules have been added to
both pages where they were missing.
The `waitUntilCalled` utility now has a timeout. It will now throw an
error if the stub is not called enough times, rather than blocking
forever.
The return type had to be changed to a function, so that we could throw
when the timeout is triggered. I tried returning an error that rejected
first, but if you don't handle the error synchronously Node.js will
consider it to be an unhandled Promise rejected (even if it _is_
handled later on).
I worked around this by resolving in the timeout case as well, so that
there is never a "deferred" Promise exception in the timeout case. The
returned function re-throws the error if it's given. That way there is
never any unhandled Promise rejection.
* Migration to remove legacy local storage keys from localStorage
* Update app/scripts/migrations/050.js
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
* Update app/scripts/migrations/050.js
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
* Fix unit tests for migration 50
* Fixing stubbing and localstorage reference in migration 50
* Update test/helper.js
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
The `errors` and `total` state has been removed from the `gas` slice,
along with related functions. It appears to have been unused for a long
time, though I'm not exactly sure as of when.
Attempts to send metrics would fail when no `options` were used. This
was because when the options parameter was not set, it was often sent
over our RPC connection as `undefined`, which gets serialized to `null`
when the message is converted to JSON. This `null` parameter didn't
trigger the default parameter set in the metametrics controller, as
default parameters are only used for `undefined`.
Instead the `options` parameter is now treated as fully optional, with
no default value set. The optional chaining operator is used to ensure
it won't blow up if it's not set. A fallback of `{}` was used for the
one destructure case as well.
The metrics e2e test would fail if the segment events still weren't
dispatched when the page loaded. The Segment events are sent on a set
interval, so it isn't abnormal for them to lag behind the page load
itself. The `waitUntilCalled` utility has been used to wait until all
required events have been dispatched.
The `wait-until-called` module was converted to an ES5 module, so that
it could be used from an e2e test. The optional `callCount` parameter
has also been added, to allow waiting for more than one call.
The `segmentSpy` had to be converted to a `segmentStub`, to allow the
`waitUntilCalled` utility to be used.
The e2e test driver used to perform the initial navigation
automatically within the `buildWebDriver` function, so that that step
wouldn't need to be repeated at the beginning of each test. However
this prevented you from doing any setup in the test before the first
navigation.
The navigation has now been moved into each individual test. It should
be functionally equivalent, except now it's possible to control exactly
when the first navigation occurs.
A 1 second delay was also removed, as it didn't seem to be necessary
when testing this. It was initially added as an attempted fix to an
intermittent failure. It did not fix that failure.
If a `gasPrice` was specified in a transaction sent via a dapp, we
would include it in our `eth_estimateGas` call, causing it to fail if
the user had insufficient balance (for either the transaction amount or
the gas fee). This resulted in the fallback gas estimate being used;
the block gas limit. The block gas limit is quite a bit larger than
most transactions need, so this resulted in wildly inflated gas costs
being shown on our confirmation screen.
The `gasPrice` has been removed from the `txParams` object we pass to
`eth_estimateGas`, so now it won't perform any balance checks anymore.
This ensures that we'll get a valid gas estimate, as long as geth is
able to simulate the contract execution properly.
Fixes#9967