-
-
Notifications
You must be signed in to change notification settings - Fork 252
feat: JsonRpcEngineV2
#6176
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
feat: JsonRpcEngineV2
#6176
Conversation
f74dff2 to
c393838
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had one more comment about typing context, but I have finally gone through everything in this PR so I believe that is the only thing that's left.
| }; | ||
|
|
||
| export type JsonRpcMiddleware< | ||
| Request extends JsonRpcCall = JsonRpcCall, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Thought] In providing default values for these parameters are we expecting engineers to be using this type directly? If so, I wonder if that is the most ergonomic approach. I wonder if we can almost always have TypeScript infer this. Maybe not something we have to improve now, but just a thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inference at the time of engine construction generally works, although if you're defining a middleware function in one place for an engine that lives elsewhere, you probably want to use this type to ensure that your middleware function is valid. Do you have any ideas as to how we would make that more ergonomic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would be curious how far we could get with removing the default values. I was mainly thinking it would reduce the size of this file. But maybe it wouldn't, and perhaps you're right that in practice it wouldn't matter as developers would need to pass in these types anyway. Like I said, just a thought as I worked with this file a bit locally, not anything concrete to suggest here.
|
|
||
| describe('requests', () => { | ||
| it('returns a result from the middleware', async () => { | ||
| const middleware: JsonRpcMiddleware<JsonRpcRequest> = jest.fn( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[Thought] I wonder if we should do another pass through these tests at some point and convert these type assertions into satisfies? I do agree with Jongsun that in general we should be promoting use of satisfies at least for non-final types instead of type assertions, so that we can have TypeScript infer as much as it can. I'd at least want the tests to serve as examples and represent best practices for how authors should define middleware.
Using a generic Result forced each middleware function to have the same return type. This makes the generic useless. Supporting this, almost all of our uses of the equivalent generic on the legacy JsonRpcMiddlware type are Json, any, or unknown. In consequence, we remove the Result generic. In addition, unfreezes the result returned from asLegacyMiddleware, a problem that was surfaced by the type refactor. Adds a test to verify this behavior.
|
|
||
| constructor({ middleware }: Options<Request>) { | ||
| // See .create() for why this is private. | ||
| private constructor({ middleware }: ConstructorOptions<Request, Context>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to entirely protect this from usage we could consider a constructor guard: https://github.com/MetaMask/key-tree/blob/main/src/SLIP10Node.ts#L517-L535
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right! I don't think we need that level of protection. It's not that the constructor is dangerous but rather that type inference won't work as well.
…r/multichain-transactions-controller * origin/main: (35 commits) feat: `JsonRpcEngineV2` (#6176) Release 641.0.0 (#6940) feat: Add transaction emulation actions (#6935) Release/640.0.0 (#6934) fix(core-backend): control randomness to fix flaky test (#6936) chore: Add `@metamask-previews/*` to NPM age gate exceptions (#6937) Release/639.0.0 (#6931) feat: make getCryptoApproveTransactionParams synchronous (#6930) feat: add new actions to `KeyringController` (#6928) feat: add `getAccounts` to `AccountsController` (#6927) chore: remove `Monad Mainnet` single call balance contract and add into account v4 (#6929) Release/638.0.0 (#6923) fix: Downgrade `multiformats` to `^9.9.0` to avoid ESM-only dependency (#6920) Release/637.0.0 (#6919) feat(account-tree-controller): add callbacks for hidden and pinned data (#6910) Release 636.0.0 (#6918) fix(core-backend): reconnection logic (#6861) fix: Tx state listener and signature coverage (#6906) Release/635.0.0 (#6917) fix(base-controller): add TypeScript declaration file for legacy module resolution (#6915) ...
Explanation
Introduces
JsonRpcEngineV2andJsonRpcServer, intended to replace all existing usage of the existingJsonRpcEngineimplementation. For the motivation behind this change, see #6088 and/or this ADR.Implementation
In order to resolve the problems listed in the motivation, V2 engine is split in two:
JsonRpcEngineV2JsonRpcServererrorHandlerconstructor parameter for capturing engine / middleware errorsSee the updated package
README.mdfor details.Migration
While this PR is substantial, migrating our existing JSON-RPC pipelines will be a significant project involving multiple teams over many releases cycles. To facilitate this, the PR introduces a forwards-compatibility adapter,
asV2Middleware(), and backwards-compatibility adapter,asLegacyMiddleware(), for the legacy and V2 engines, respectively. In addition, all V2 exports are exposed under the/v2export path, making this update completely non-breaking (although all legacy exports are deprecated).Note to reviewers
I recommend proceeding as follows:
JsonRpcEngineV2JsonRpcServerReferences
JsonRpcEnginefor safety, ergonomics, and debuggability #6088JsonRpcEngineChecklist
I've prepared draft pull requests for clients and consumer packages to resolve any breaking changesNote
Introduces a new v2 JSON-RPC engine and server, adds two-way adapters with the legacy engine, updates exports/docs, and adds supporting utilities, tests, and dependencies.
JsonRpcEngineV2for middleware orchestration andJsonRpcServerfor spec-compliant request/response handling.MiddlewareContext, utility types/helpers (isRequest,isNotification,JsonRpcEngineError,stringify), and composition APIs (asMiddleware,handle).asLegacyMiddleware(use V2 in legacy engine) andasV2Middleware(use legacy engine in V2).JsonRpcEngineand related types as deprecated; uses sharedstringifyutil; minor test/ESLint adjustments.exportsentry"./v2"and Browserify shimv2.js.indexand newv2/indexexports; addssrc/README.mdfor legacy andv2/README.md.README.mdwith V2 usage and migration notes;CHANGELOG.mdnotes Added (V2) and Deprecated (legacy).deep-freeze-strict,klona, and@types/deep-freeze-strict.Written by Cursor Bugbot for commit 04fdf3b. This will update automatically on new commits. Configure here.