Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Jsonrpc errors get burried inside error.message string #15250

Open
BelfordZ opened this issue Jul 15, 2022 · 4 comments
Open

[Bug]: Jsonrpc errors get burried inside error.message string #15250

BelfordZ opened this issue Jul 15, 2022 · 4 comments
Labels
needs-decision Needs a decision from MetaMask in order to proceed. type-enhancement

Comments

@BelfordZ
Copy link
Contributor

BelfordZ commented Jul 15, 2022

Describe the bug

Problem

Errors returned from ethereum JSON-RPC api providers, when not expected by ethjs-query, are in a hard to use format.

Using localhost, or using addEthereumNetwork means we have no control over the responses, and thus should hold minimal expectation over their results / errors. While this issue is most prevelant among users who are connecting to ganache or hardhat, you can also get this error by setting too low of gas while using an infura provider.

Examples

  1. smart contract call that executes and reverts with a reason: invalid opcode. Any developer will see this when they are connected to ganache and trying their dapp:
REQUEST:
{
  "jsonrpc": "2.0",
  "method": "eth_sendTransaction",
  "params": [
    {
      "from": "0xaa49f066a49677c0165ea0788ad0425426e2d4b5",
      "to": "0x56f50fa1a91a48d8a55ded4c3cb3d179ca99d05a",
      "value": "0x0"
    }
  ],
  "id": 0
}
RESPONSE:
{
  "id": 0,
  "error": {
    "code": -32603,
    "message": "[ethjs-query] while formatting outputs from RPC '{\"value\":{\"code\":-32603,\"data\":{\"message\":\"VM Exception while processing transaction: invalid opcode\",\"code\":-32000,\"data\":{\"0x877c456d0b406f0706f405b0d2eb4e0ebc69629a539503e7ad94a7f9b6ba36af\":{\"error\":\"invalid opcode\",\"program_counter\":13,\"return\":\"0x\"},\"stack\":\"c: VM Exception while processing transaction: invalid opcode\\n    at Function.c.fromResults (/home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:4:192416)\\n    at w.processBlock (/home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:50915)\\n    at processTicksAndRejections (node:internal/process/task_queues:96:5)\",\"name\":\"c\"}}}}'"
  }
}

  1. Manually setting a bad nonce as an example of non-contract call error
REQUEST:
<same as above, but set the nonce to something really high in MM>

RESPONSE:
{
  "jsonrpc": "2.0",
  "id": 0,
  "error": {
    "code": -32603,
    "message": "[ethjs-query] while formatting outputs from RPC '{\"value\":{\"code\":-32603,\"data\":{\"message\":\"the tx doesn't have the correct nonce. account has nonce of: 0 tx has nonce of: 67676\",\"code\":-32000,\"data\":{\"stack\":\"n: the tx doesn't have the correct nonce. account has nonce of: 0 tx has nonce of: 67676\\n    at i (/home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:219953)\\n    at /home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:55:220084\\n    at /home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:48915\\n    at /home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:224017\\n    at /home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:227782\\n    at Object.return (/home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:227355)\\n    at /home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:225688\\n    at e (/home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:227723)\\n    at /home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:227704\\n    at /home/zb/code/masa/smart-contracts/node_modules/ganache-cli/build/ganache-core.node.cli.js:42:224856\\n    at processTicksAndRejections (node:internal/process/task_queues:78:11)\",\"name\":\"n\"}}}}'"
  }
}

The useful parts of the error messages are inside of a string, and doubly nested.

Possible Solutions

  1. Fix the issue in the most common case by directly handling the error
  • Pros:
  • Cons:
    • leaves other places possibly also giving these bad errors
    • does little to address the actual problem, more of a bandaid.

1.b Same as 1, except leave error.message as is (to not break things), and parse the string out same way as in the PR, but put the result insdie of error.data.

  • Pros
    • non-breaking
    • gives developers something slightly better than string parsing error.message
  • Cons
    • still a garbage error that we are passing to the end user, they have to dig into it to find anything useful still.

  1. Update ethjs-query to no longer wrap errors inside result.value, and handle unrecognized errors better by not stringifying the error.
  • Pros:
    • simple and fixes the issue in all places at once
  • Cons:
    • the project has not made a release in 4 years, and from comments on issues, is frozen.

  1. 'Strangle' ethjs-query by making a wrapper for it, handling the errors as we want, and replacing all the calls to new EthjsQuery in extension.
  • Pros:
    • Dont need to unfreeze ethjs
    • Doesn't affect any other places that are using ethjs-query
    • keeps the difference between errors returned by different node impls contained
    • simple to implement
    • gives us a single place to change when/if we decide to replace ethjsquery
  • Cons:
    • Doesn't get rid of or improve the underlying lib being no longer supported
    • another layer of abstraction between api call -> result

  1. Replace ethjs-query with ethers (which is what ethjs-query recommends using)
  • Pros:
    • externally maintained and widely used
  • Cons:
    • includes a lot more than we need
    • doenst give us the same thing - would require a lot of work to get it working
    • scope of change fairly significant

  1. Replace ethjs-query with @open-rpc/client-js as a generic json-rpc client
  • Pros:
    • externally maintained and widely used
    • batching support
    • Custom transport sopport allows us to faily easily integrate with networkController's this.provder (json-rpc-engine)
    • doesnt modify the request / result / error, just passes it along
  • Cons:
    • doesnt provide the same interface (request({method: "eth_sendRawTransaction"}) vs. client.eth_sendRawTransaction)

  1. Replace ethjs-query with an openrpc generated client.
  • Pros:
    • Generated from an openrpc document which describes the 'base ethereum json rpc'.
    • uses client-js, so all the same features (batching and what not)
    • json schema validation on parameters makes us able to give standardized errors about bad params before hitting rpc endpoint
    • fully typed (also generates all the types involved in eth json rpc)
    • matches interface being used in ethjs-query
    • clearly communicates to client / test client developers what json-rpc api metamask is expecting of them.
  • Cons:
    • Using generated code isnt everyones cup of tea
    • scope of change fairly significant

Proposed way forward

  1. implement option 2 first.
  2. use the strangled interface to impl client-js or generated client as a replacement

Steps to reproduce

(this is just one way to make it happen, but it happens on infura endpoints when making contract calls with a gas setting thats too low)

  1. start ganache or hardhat
  2. switch metamask to localhost
  3. go to test dapp, deploy failing contract, get the deployed contract address from devtools console
  4. go to https://metamask.github.io/api-playground/api-documentation/
  5. click try it now button on request permissions
  6. click play
  7. open metamask, copy your metamask addr
  8. click try it now on the sendTransaction method
  9. use the testdapp failing contract address as the to address
  10. use your address for "from"
  11. use value "0x0"
  12. click play
  13. send transaction
  14. observe error that is received
@bschorchit
Copy link

@worldlyjohn was thinking about something similar so we also get more digested error messages on Mixpanel and can more easily work on addressing the underlying issues.

@bschorchit bschorchit added type-enhancement needs-decision Needs a decision from MetaMask in order to proceed. and removed type-bug labels Jul 18, 2022
@kumavis
Copy link
Member

kumavis commented Jul 18, 2022

im open to 1, 1b, 2, 5

@BelfordZ
Copy link
Contributor Author

2 seems ideal. Will move forward with that

@Gudahtt
Copy link
Member

Gudahtt commented Aug 1, 2022

The problem statement here seems to be that these errors are too difficult to read, but that might be the wrong problem. Most of these errors should never reach the dapp API in the first place. I'm less concerned that our internal errors are readable than I am in reducing the number of internal errors we have. We should not have internal errors. Contract errors, network errors, input validation, etc. should be explicitly handled by us and exposed as the appropriate JSON-RPC/Ethereum provider error, with a nice readable error message. These are situations we can anticipate and handle.

brad-decker added a commit that referenced this issue Sep 26, 2023
## **Description**
Our fork of ethjs-query has been namespaced to the `@metamask/`
namespace, and updated with mostly development only fixes. There is one
exception which is the reason for this pull request which is the removal
of a try/catch that was catching too broadly and wrapping legitimate
errors in a new Error object that claimed the issue was with the
formatting of the output. In most cases this is incorrect and results in
a wide swath of errors being lumped together inside of sentry. This
change will result in the real errors being surfaced, after which we can
decide where to prioritize efforts to resolve RPC issues.

This PR progresses, and is expected to change the stack trace for the
following issues:
#9317 
#10519 
#10619
#11488 
#11974 
#13395 
#14298 
#14365 
#15250 
#17073 
#17803 
#19697 
#20699 

We are closing these issues opened automatically by sentry-io which are
not fully resolved but should result in better errors and stack traces:

fixes #10552 
fixes #14660 
fixes #14676 
fixes #14730 
fixes #14801
fixes #15065 

## **Manual testing steps**
1. Attempt to reproduce any of the bugs listed, 17073 was the easiest to
reproduce for me. This involves getting test currency from the wemix
faucet as listed in the issue and initiating a transaction between two
accounts you own.
2. On develop you'll see an 'error formatting outputs' error text
similar to what is reported in the issue.
3. On this branch you'll get the original error, without the wrapped
'formatting' error. including a different stack trace.

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained:
  - [x] What problem this PR is solving.
  - [x] How this problem was solved.
  - [x] How reviewers can test my changes.
- [x] I’ve indicated what issue this PR is linked to: Fixes #???
- [x] I’ve included tests if applicable.
- [x] I’ve documented any added code.
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
- [x] I’ve properly set the pull request status:
  - [ ] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

---------

Co-authored-by: MetaMask Bot <[email protected]>
github-merge-queue bot pushed a commit that referenced this issue Oct 18, 2024
#22875)

## **Description**

## **Related issues**

- #27784
- MetaMask/eth-json-rpc-middleware#335
- #27917
- #18510
- #15250
- MetaMask/metamask-improvement-proposals#36

### Blocked by
- [x] #24496

### Follow-up to
- #24496

## **Manual testing steps**

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained what problem this PR is solving and how it
is solved.
- [x] I've linked related issues
- [x] I've included manual testing steps
- [x] I've included screenshots/recordings if applicable
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [x] I’ve properly set the pull request status:
  - [x] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
vinistevam pushed a commit that referenced this issue Oct 20, 2024
#22875)

## **Description**

## **Related issues**

- #27784
- MetaMask/eth-json-rpc-middleware#335
- #27917
- #18510
- #15250
- MetaMask/metamask-improvement-proposals#36

### Blocked by
- [x] #24496

### Follow-up to
- #24496

## **Manual testing steps**

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained what problem this PR is solving and how it
is solved.
- [x] I've linked related issues
- [x] I've included manual testing steps
- [x] I've included screenshots/recordings if applicable
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [x] I’ve properly set the pull request status:
  - [x] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Gudahtt pushed a commit that referenced this issue Oct 21, 2024
#22875)

- #27784
- MetaMask/eth-json-rpc-middleware#335
- #27917
- #18510
- #15250
- MetaMask/metamask-improvement-proposals#36

- [x] #24496

- #24496

- [x] I’ve followed [MetaMask Coding
Standards](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've clearly explained what problem this PR is solving and how it
is solved.
- [x] I've linked related issues
- [x] I've included manual testing steps
- [x] I've included screenshots/recordings if applicable
- [x] I’ve included tests if applicable
- [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-extension/blob/develop/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
- [x] I’ve properly set the pull request status:
  - [x] In case it's not yet "ready for review", I've set it to "draft".
- [x] In case it's "ready for review", I've changed it from "draft" to
"non-draft".

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-decision Needs a decision from MetaMask in order to proceed. type-enhancement
Projects
None yet
Development

No branches or pull requests

4 participants