-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement async mode for generateWallet #231
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import * as http from 'http'; | ||
| import express from 'express'; | ||
| import { listen, close } from './servers'; | ||
|
|
||
| export interface MockBridgeCall { | ||
| method: string; | ||
| path: string; | ||
| body: unknown; | ||
| } | ||
|
|
||
| export interface MockBridgeServer { | ||
| port: number; | ||
| calls: MockBridgeCall[]; | ||
| close(): Promise<void>; | ||
| } | ||
|
|
||
| export async function startMockBridgeServer(): Promise<MockBridgeServer> { | ||
| const calls: MockBridgeCall[] = []; | ||
|
|
||
| const app = express(); | ||
| app.use(express.json()); | ||
|
|
||
| app.use((req, _res, next) => { | ||
| calls.push({ method: req.method, path: req.path, body: req.body }); | ||
| next(); | ||
| }); | ||
|
|
||
| app.post('*', (_req, res) => { | ||
| res.status(202).json({ jobId: 'test-job-id' }); | ||
| }); | ||
|
|
||
| const server = http.createServer(app); | ||
| const port = await listen(server); | ||
|
|
||
| return { port, calls, close: () => close(server) }; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,8 @@ import { orchestrateEcdsaKeyGen } from './ecdsa'; | |
| import { orchestrateEddsaKeyGen } from './eddsa'; | ||
| import coinFactory from '../../shared/coinFactory'; | ||
| import { BadRequestError } from '../../shared/errors'; | ||
| import { KeySource } from '../../shared/types'; | ||
| import { submitJobViaBridgeClient } from './utils/asyncUtils'; | ||
|
|
||
| /** | ||
| * Request handler for generating an advanced wallet. | ||
|
|
@@ -40,6 +42,16 @@ export async function handleGenerateWallet( | |
| async function handleGenerateOnChainWallet( | ||
| req: MasterApiSpecRouteRequest<'v1.wallet.generate', 'post'>, | ||
| ) { | ||
| const asyncResult = await submitJobViaBridgeClient(req, { | ||
| path: `/api/${req.params.coin}/key/independent`, | ||
| body: req.decoded, | ||
| sources: [KeySource.USER, KeySource.BACKUP], | ||
| operationType: 'multisig_keygen', | ||
| }); | ||
|
Comment on lines
+45
to
+50
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is req.decoded the correct bridge body (not some other trimmed/transformed payload)?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we're supposed to send the request as is - believe the typing is unknown 🤔 |
||
| if (asyncResult) { | ||
| return asyncResult; | ||
| } | ||
|
|
||
| const bitgo = req.bitgo; | ||
| const baseCoin = await coinFactory.getCoin(req.params.coin, bitgo); | ||
|
|
||
|
|
@@ -144,6 +156,10 @@ async function handleGenerateOnChainWallet( | |
| async function handleGenerateMpcWallet( | ||
| req: MasterApiSpecRouteRequest<'v1.wallet.generate', 'post'>, | ||
| ) { | ||
| if (req.config.asyncModeConfig.enabled) { | ||
| throw new BadRequestError('Async mode is not yet supported for TSS wallet generation'); | ||
| } | ||
|
|
||
|
Comment on lines
+159
to
+162
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add unit tests for async guards |
||
| const bitgo = req.bitgo; | ||
| const baseCoin = await coinFactory.getCoin(req.decoded.coin, bitgo); | ||
| const awmClient = req.awmUserClient; | ||
|
|
@@ -227,6 +243,10 @@ async function handleGenerateMpcWallet( | |
| async function handleGenerateEvmKeyRingWallet( | ||
| req: MasterApiSpecRouteRequest<'v1.wallet.generate', 'post'>, | ||
| ) { | ||
| if (req.config.asyncModeConfig.enabled) { | ||
| throw new BadRequestError('Async mode is not yet supported for EVM keyring wallet generation'); | ||
| } | ||
|
|
||
| const bitgo = req.bitgo; | ||
| const baseCoin = await coinFactory.getCoin(req.decoded.coin, bitgo); | ||
| if (!baseCoin.isEVM()) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import { SubmitParams } from '../../clients/bridgeClient.types'; | ||
| import { BitGoRequest } from '../../../types/request'; | ||
| import { MasterExpressConfig } from '../../../shared/types'; | ||
|
|
||
| export const ASYNC_JOB_SUBMITTED_STATUS = 'pending' as const; | ||
| export type AsyncJobSubmittedStatus = typeof ASYNC_JOB_SUBMITTED_STATUS; | ||
| export type AsyncJobResponse = { jobId: string; status: AsyncJobSubmittedStatus }; | ||
|
|
||
| /** | ||
| * Submits a signing or keygen job to the bridge and returns { jobId, status: 'pending' }. | ||
| * Returns null when async mode is off — callers must fall through to the sync path in that case. | ||
| */ | ||
| export async function submitJobViaBridgeClient( | ||
| req: BitGoRequest<MasterExpressConfig>, | ||
| params: SubmitParams, | ||
| ): Promise<AsyncJobResponse | null> { | ||
| if (!req.config.asyncModeConfig.enabled) return null; | ||
| if (!req.bridgeClient) { | ||
| throw new Error('bridgeClient is required when async mode is enabled'); | ||
| } | ||
| const { jobId } = await req.bridgeClient.submit(params); | ||
| return { jobId, status: ASYNC_JOB_SUBMITTED_STATUS }; | ||
| } |
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.
assert async tests for bridge contract (header and body) as we just have jobId and status here now.