Skip to content

Commit 2b0166c

Browse files
committed
chore: update async worker to use callbacks
This commit refactors the async job worker to utilize callbacks for keychain creation and wallet addition. Ticket: WCN-746
1 parent 04d78b5 commit 2b0166c

5 files changed

Lines changed: 66 additions & 120 deletions

File tree

src/__tests__/api/master/asyncJobWorker.test.ts

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const POLL_INTERVAL_MS = 1000;
2121
function makeUserKeychain() {
2222
return {
2323
id: 'user-key-id',
24-
pub: 'xpub_user',
24+
pub: 'xpub661MyMwAqRbcEvJQx6spkkHLRgtjxmVdyDSvbDt2m9NFpbkHdcu5WJsHHHqFxNATbNHnhMWJiwckoMqF75EpcNhU9xeVM4oDS7urM3os4BH',
2525
encryptedPrv: 'encrypted-user-prv',
2626
type: 'independent' as const,
2727
source: 'user' as const,
@@ -32,7 +32,7 @@ function makeUserKeychain() {
3232
function makeBackupKeychain() {
3333
return {
3434
id: 'backup-key-id',
35-
pub: 'xpub_backup',
35+
pub: 'xpub661MyMwAqRbcFnihegj1Mo2ePZoMQyLbBYpW7gDXZ7qzqxF3FBAkNAP8Gki8Mxx2BVLjN3RRa75pt5apD2g3ewXPrCfdssAJ7VupXqucLsb',
3636
encryptedPrv: 'encrypted-backup-prv',
3737
type: 'independent' as const,
3838
source: 'backup' as const,
@@ -215,19 +215,27 @@ describe('asyncJobWorker', () => {
215215
.query({ status: 'awaiting_bitgo' })
216216
.reply(200, { jobs: [job1, job2] });
217217

218-
nockBitgoKeychainRegistration({ pub: 'xpub_user', source: 'user', keyId: 'user-key-id' });
219218
nockBitgoKeychainRegistration({
220-
pub: 'xpub_backup',
219+
pub: makeUserKeychain().pub,
220+
source: 'user',
221+
keyId: 'user-key-id',
222+
});
223+
nockBitgoKeychainRegistration({
224+
pub: makeBackupKeychain().pub,
221225
source: 'backup',
222226
keyId: 'backup-key-id',
223227
});
224228
nockBitgoKeyCreate('bitgo-key-id');
225229
nockWalletAdd('wallet-1');
226230
nockUpdateJobComplete('job-1', 'wallet-1');
227231

228-
nockBitgoKeychainRegistration({ pub: 'xpub_user', source: 'user', keyId: 'user-key-id' });
229232
nockBitgoKeychainRegistration({
230-
pub: 'xpub_backup',
233+
pub: makeUserKeychain().pub,
234+
source: 'user',
235+
keyId: 'user-key-id',
236+
});
237+
nockBitgoKeychainRegistration({
238+
pub: makeBackupKeychain().pub,
231239
source: 'backup',
232240
keyId: 'backup-key-id',
233241
});
@@ -254,9 +262,13 @@ describe('asyncJobWorker', () => {
254262

255263
nockUpdateJobFailed('job-bad');
256264

257-
nockBitgoKeychainRegistration({ pub: 'xpub_user', source: 'user', keyId: 'user-key-id' });
258265
nockBitgoKeychainRegistration({
259-
pub: 'xpub_backup',
266+
pub: makeUserKeychain().pub,
267+
source: 'user',
268+
keyId: 'user-key-id',
269+
});
270+
nockBitgoKeychainRegistration({
271+
pub: makeBackupKeychain().pub,
260272
source: 'backup',
261273
keyId: 'backup-key-id',
262274
});
@@ -289,12 +301,12 @@ describe('asyncJobWorker', () => {
289301
const walletId = 'new-wallet-id';
290302

291303
const userKeyNock = nockBitgoKeychainRegistration({
292-
pub: 'xpub_user',
304+
pub: makeUserKeychain().pub,
293305
source: 'user',
294306
keyId: 'user-key-id',
295307
});
296308
const backupKeyNock = nockBitgoKeychainRegistration({
297-
pub: 'xpub_backup',
309+
pub: makeBackupKeychain().pub,
298310
source: 'backup',
299311
keyId: 'backup-key-id',
300312
});
@@ -367,9 +379,13 @@ describe('asyncJobWorker', () => {
367379
});
368380
const walletId = 'ent-wallet-id';
369381

370-
nockBitgoKeychainRegistration({ pub: 'xpub_user', source: 'user', keyId: 'user-key-id' });
371382
nockBitgoKeychainRegistration({
372-
pub: 'xpub_backup',
383+
pub: makeUserKeychain().pub,
384+
source: 'user',
385+
keyId: 'user-key-id',
386+
});
387+
nockBitgoKeychainRegistration({
388+
pub: makeBackupKeychain().pub,
373389
source: 'backup',
374390
keyId: 'backup-key-id',
375391
});

src/__tests__/integration/asyncJobWorker.integ.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function makeAwaitingBitgoJob(overrides: Partial<BridgeJobResponse> = {}): Bridg
4040
status: 200,
4141
body: {
4242
id: 'user-key-id',
43-
pub: 'xpub_user',
43+
pub: 'xpub661MyMwAqRbcEvJQx6spkkHLRgtjxmVdyDSvbDt2m9NFpbkHdcu5WJsHHHqFxNATbNHnhMWJiwckoMqF75EpcNhU9xeVM4oDS7urM3os4BH',
4444
type: 'independent',
4545
source: 'user',
4646
coin: COIN,
@@ -50,7 +50,7 @@ function makeAwaitingBitgoJob(overrides: Partial<BridgeJobResponse> = {}): Bridg
5050
status: 200,
5151
body: {
5252
id: 'backup-key-id',
53-
pub: 'xpub_backup',
53+
pub: 'xpub661MyMwAqRbcFnihegj1Mo2ePZoMQyLbBYpW7gDXZ7qzqxF3FBAkNAP8Gki8Mxx2BVLjN3RRa75pt5apD2g3ewXPrCfdssAJ7VupXqucLsb',
5454
type: 'independent',
5555
source: 'backup',
5656
coin: COIN,
@@ -80,7 +80,7 @@ describe('asyncJobWorker: end-to-end polling', () => {
8080
services.bridge.calls.length = 0;
8181
});
8282

83-
it('picks up an awaiting_bitgo keygen job, registers keychains, creates wallet, and PATCHes complete', async () => {
83+
it('picks up an awaiting_bitgo keygen job, creates wallet, and PATCHes complete', async () => {
8484
const jobId = 'integ-job-123';
8585
assert(services.bridge, 'bridge service should be defined');
8686
services.bridge.setPendingJobs([makeAwaitingBitgoJob()]);
Lines changed: 0 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,3 @@
1-
import {
2-
Keychain,
3-
KeychainsTriplet,
4-
promiseProps,
5-
RequestTracer,
6-
SupplementGenerateWalletOptions,
7-
Wallet,
8-
WalletWithKeychains,
9-
} from '@bitgo-beta/sdk-core';
10-
import { BitGoAPI } from '@bitgo-beta/sdk-api';
11-
import _ from 'lodash';
12-
import { IndependentKeychainResponse } from '../../clients/advancedWalletManagerClient';
13-
import coinFactory from '../../../shared/coinFactory';
14-
151
export function getBaseWalletParams(multisigType: 'onchain' | 'tss') {
162
return { m: 2, n: 3, keys: [] as string[], type: 'advanced', multisigType } as const;
173
}
18-
19-
export interface RegisterKeychainsAndCreateWalletParams {
20-
coin: string;
21-
bitgo: BitGoAPI;
22-
userKeychain: IndependentKeychainResponse;
23-
backupKeychain: IndependentKeychainResponse;
24-
walletParams: SupplementGenerateWalletOptions;
25-
isDistributedCustody?: boolean;
26-
}
27-
28-
export async function registerKeychainsAndCreateWallet({
29-
bitgo,
30-
coin,
31-
walletParams,
32-
userKeychain,
33-
backupKeychain,
34-
isDistributedCustody,
35-
}: RegisterKeychainsAndCreateWalletParams): Promise<WalletWithKeychains> {
36-
const baseCoin = await coinFactory.getCoin(coin, bitgo);
37-
const reqId = new RequestTracer();
38-
39-
const registerKeychain = async (keyChain: IndependentKeychainResponse): Promise<Keychain> => {
40-
const registered = await baseCoin.keychains().add({
41-
pub: keyChain.pub,
42-
keyType: keyChain.type,
43-
source: keyChain.source,
44-
reqId,
45-
});
46-
return _.extend({}, registered, keyChain);
47-
};
48-
49-
const {
50-
userKeychain: registeredUser,
51-
backupKeychain: registeredBackup,
52-
bitgoKeychain,
53-
}: KeychainsTriplet = await promiseProps({
54-
userKeychain: registerKeychain(userKeychain),
55-
backupKeychain: registerKeychain(backupKeychain),
56-
bitgoKeychain: baseCoin.keychains().createBitGo({
57-
enterprise: walletParams.enterprise,
58-
keyType: 'independent',
59-
reqId,
60-
isDistributedCustody,
61-
}),
62-
});
63-
64-
const keychains: KeychainsTriplet = {
65-
userKeychain: registeredUser,
66-
backupKeychain: registeredBackup,
67-
bitgoKeychain,
68-
};
69-
70-
const finalWalletParams = await baseCoin.supplementGenerateWallet(
71-
{ ...walletParams, keys: [registeredUser.id, registeredBackup.id, bitgoKeychain.id] },
72-
keychains,
73-
);
74-
75-
bitgo.setRequestTracer(reqId);
76-
const newWallet = await bitgo.post(baseCoin.url('/wallet/add')).send(finalWalletParams).result();
77-
78-
return {
79-
wallet: new Wallet(bitgo, baseCoin, newWallet),
80-
userKeychain: registeredUser,
81-
backupKeychain: registeredBackup,
82-
bitgoKeychain,
83-
responseType: 'WalletWithKeychains',
84-
};
85-
}

src/masterBitgoExpress/handlers/walletGenerationCallbacks.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { CreateKeychainCallback } from '@bitgo-beta/sdk-core';
22
import { KeySource } from '../../shared/types';
3-
import { AdvancedWalletManagerClient } from '../clients/advancedWalletManagerClient';
3+
import {
4+
AdvancedWalletManagerClient,
5+
IndependentKeychainResponse,
6+
} from '../clients/advancedWalletManagerClient';
47

58
export function createOnchainKeyGenCallback(
69
awmUserClient: AdvancedWalletManagerClient,
@@ -20,3 +23,20 @@ export function createOnchainKeyGenCallback(
2023
return keychain as { pub: string; type: 'independent'; source: typeof source };
2124
};
2225
}
26+
27+
export function createOnchainKeyGenCallbackForPreGeneratedKeychains(
28+
preGeneratedKeychains: Record<KeySource.USER | KeySource.BACKUP, IndependentKeychainResponse>,
29+
): CreateKeychainCallback {
30+
return async ({ source, coin: _ }) => {
31+
if (!(source in preGeneratedKeychains)) {
32+
throw new Error(`${source} keychain not available for onchain key generation`);
33+
}
34+
35+
const keychain = preGeneratedKeychains[source];
36+
return {
37+
source,
38+
pub: keychain.pub,
39+
type: 'independent',
40+
};
41+
};
42+
}

src/masterBitgoExpress/workers/asyncJobWorker.ts

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
1-
import { CreateBitGoOptions, SupplementGenerateWalletOptions } from '@bitgo-beta/sdk-core';
21
import { BitGoAPI } from '@bitgo-beta/sdk-api';
32
import { OsoBridgeClient } from '../clients/bridgeClient';
43
import { AwmResponseSchema, BridgeJobResponse } from '../clients/bridgeClient.types';
54
import {
65
IndependentKeychainResponseSchema,
76
type IndependentKeychainResponse,
87
} from '../clients/advancedWalletManagerClient';
9-
import {
10-
getBaseWalletParams,
11-
registerKeychainsAndCreateWallet,
12-
} from '../handlers/utils/walletCreationUtils';
8+
import coinFactory from '../../shared/coinFactory';
139
import { MasterExpressConfig } from '../../shared/types';
1410
import logger from '../../shared/logger';
11+
import { createOnchainKeyGenCallbackForPreGeneratedKeychains } from '../handlers/walletGenerationCallbacks';
1512

1613
const ASYNC_OPERATIONS_TO_HANDLERS: Partial<
1714
Record<
@@ -116,31 +113,26 @@ export async function handleKeyGenerationOperation(
116113
const backupKeychain = parseKeychainFromAwmResponse(job.awmBackupResponse, 'awmBackupResponse');
117114
const { jobId, coin, version } = job;
118115

119-
const requestBody = (job.request?.body ?? {}) as unknown as SupplementGenerateWalletOptions &
120-
Pick<CreateBitGoOptions, 'isDistributedCustody'>;
121-
122-
const walletParams: SupplementGenerateWalletOptions = {
123-
...requestBody,
124-
...getBaseWalletParams('onchain'),
125-
};
126-
127-
const result = await registerKeychainsAndCreateWallet({
128-
bitgo,
129-
walletParams,
130-
userKeychain,
131-
backupKeychain,
132-
coin,
133-
isDistributedCustody: requestBody.isDistributedCustody,
116+
const baseCoin = await coinFactory.getCoin(coin, bitgo);
117+
const result = await baseCoin.wallets().generateWallet({
118+
...(job.request?.body ?? {}),
119+
type: 'advanced',
120+
multisigType: 'onchain',
121+
createKeychainCallback: createOnchainKeyGenCallbackForPreGeneratedKeychains({
122+
user: userKeychain,
123+
backup: backupKeychain,
124+
}),
134125
});
135126

136127
logger.info(`${logPrefix} job ${jobId} created wallet - updating job status to complete`);
128+
const walletId = result.wallet.toJSON().id;
137129

138130
await bridge.updateJob({
139131
jobId,
140132
version,
141133
status: 'complete',
142-
result: { walletId: result.wallet.id() },
134+
result: { walletId },
143135
});
144136

145-
logger.info(`${logPrefix} job ${jobId} complete, walletId ${result.wallet.id()}`);
137+
logger.info(`${logPrefix} job ${jobId} complete, walletId ${walletId}`);
146138
}

0 commit comments

Comments
 (0)