From 7da654649d2fd44761c803ace71089ea9b9765d4 Mon Sep 17 00:00:00 2001 From: Felicio Mununga Date: Tue, 26 Mar 2024 14:28:54 +0900 Subject: [PATCH] iterate entity metadata sequentially (#543) * iterate entity metadata sequentially * r * c --- .changeset/forty-wasps-refuse.md | 5 + examples/with-next/pages/index.tsx | 5 +- examples/with-vite/src/app.tsx | 5 +- packages/status-js/src/client/client.ts | 4 +- packages/status-js/src/consts/peers.ts | 1 + .../src/request-client/request-client.ts | 279 +++++++++--------- 6 files changed, 149 insertions(+), 150 deletions(-) create mode 100644 .changeset/forty-wasps-refuse.md diff --git a/.changeset/forty-wasps-refuse.md b/.changeset/forty-wasps-refuse.md new file mode 100644 index 00000000..e34e46fc --- /dev/null +++ b/.changeset/forty-wasps-refuse.md @@ -0,0 +1,5 @@ +--- +'@status-im/js': patch +--- + +iterate metadata sequentially diff --git a/examples/with-next/pages/index.tsx b/examples/with-next/pages/index.tsx index 408af486..332cbc38 100644 --- a/examples/with-next/pages/index.tsx +++ b/examples/with-next/pages/index.tsx @@ -9,7 +9,10 @@ if (!publicKey) { ) } -const environment = process.env.NEXT_PUBLIC_ENVIRONMENT as 'production' | 'test' +const environment = process.env.NEXT_PUBLIC_ENVIRONMENT as + | 'development' + | 'preview' + | 'production' /** * For some reason the regular import fails with a server error: diff --git a/examples/with-vite/src/app.tsx b/examples/with-vite/src/app.tsx index b4c9a7aa..773b76c2 100644 --- a/examples/with-vite/src/app.tsx +++ b/examples/with-vite/src/app.tsx @@ -8,7 +8,10 @@ if (!publicKey) { ) } -const environment = process.env.ENVIRONMENT as 'production' | 'test' +const environment = process.env.ENVIRONMENT as + | 'development' + | 'preview' + | 'production' export const App = () => { return ( diff --git a/packages/status-js/src/client/client.ts b/packages/status-js/src/client/client.ts index 00b6b196..58f8fbdd 100644 --- a/packages/status-js/src/client/client.ts +++ b/packages/status-js/src/client/client.ts @@ -132,7 +132,7 @@ class Client { } static async start(options: ClientOptions): Promise { - // const { environment = 'development' } = options + const { environment = 'development' } = options let waku: LightNode | undefined let client: Client | undefined @@ -161,7 +161,7 @@ class Client { * >@see https://forum.vac.dev/t/waku-v2-scalability-studies/142/2 */ bootstrap({ - list: peers['production'], + list: peers[environment], timeout: 0, // note: Infinity prevents connection // tagTTL: Infinity, diff --git a/packages/status-js/src/consts/peers.ts b/packages/status-js/src/consts/peers.ts index 39bbfe89..0ef0a872 100644 --- a/packages/status-js/src/consts/peers.ts +++ b/packages/status-js/src/consts/peers.ts @@ -14,6 +14,7 @@ const production = [ '/dns4/store-02.ac-cn-hongkong-c.shards.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAm9CQhsuwPR54q27kNj9iaQVfyRzTGKrhFmr94oD8ujU6P', ] +// todo?: https://github.com/status-im/infra-shards/issues/29#issuecomment-1992729489 `shards.staging`; await integration in desktop and mobile // note!: users may experience additional latency due to cross-regional connection // todo: use "dynamic" discovery protocol instead // todo?: use a regional map together with an environment variable for the peer selection (e.g. `VERCEL_REGION`, but probably limited to Serverless Functions) diff --git a/packages/status-js/src/request-client/request-client.ts b/packages/status-js/src/request-client/request-client.ts index 302c166a..6ca2ce85 100644 --- a/packages/status-js/src/request-client/request-client.ts +++ b/packages/status-js/src/request-client/request-client.ts @@ -37,7 +37,7 @@ import type { LightNode } from '@waku/interfaces' export interface RequestClientOptions { ethProviderApiKey: string - // environment?: 'development' | 'preview' | 'production' + environment?: 'development' | 'preview' | 'production' } class RequestClient { @@ -72,7 +72,7 @@ class RequestClient { } static async start(options: RequestClientOptions): Promise { - // const { environment = 'development' } = options + const { environment = 'development' } = options let waku: LightNode | undefined let client: RequestClient | undefined @@ -89,7 +89,7 @@ class RequestClient { libp2p: { peerDiscovery: [ bootstrap({ - list: peers['production'], + list: peers[environment], timeout: 0, // note: Infinity prevents connection // tagTTL: Infinity, @@ -205,104 +205,99 @@ class RequestClient { const contentTopic = idToContentTopic(communityPublicKey) const symmetricKey = await generateKeyFromPassword(communityPublicKey) - let communityDescription: CommunityDescription | undefined = undefined - try { - // todo: use queryGenerator() instead - await this.waku.store.queryWithOrderedCallback( - [ - createDecoder(contentTopic, symmetricKey, { - clusterId: 16, - shard: 32, - }), - ], - async wakuMessage => { - // handle - const message = this.handleWakuMessage(wakuMessage) + const wakuMessageGenerator = this.waku.store.queryGenerator([ + createDecoder(contentTopic, symmetricKey, { + clusterId: 16, + shard: 32, + }), + ]) + for await (const wakuMessages of wakuMessageGenerator) { + for await (const wakuMessage of wakuMessages) { + if (!wakuMessage) { + continue + } - if (!message) { - return - } + // handle + const message = this.handleWakuMessage(wakuMessage) + if (!message) { + continue + } - if ( - message.type !== - ApplicationMetadataMessage_Type.COMMUNITY_DESCRIPTION - ) { - return - } + if ( + message.type !== ApplicationMetadataMessage_Type.COMMUNITY_DESCRIPTION + ) { + continue + } - // decode - const decodedCommunityDescription = CommunityDescription.fromBinary( - message.payload + // decode + const decodedCommunityDescription = CommunityDescription.fromBinary( + message.payload + ) + + // validate + if ( + !isClockValid( + BigInt(decodedCommunityDescription.clock), + message.timestamp + ) + ) { + continue + } + + if (isEncrypted(decodedCommunityDescription.tokenPermissions)) { + // todo?: zod + const permission = Object.values( + decodedCommunityDescription.tokenPermissions + ).find( + permission => + permission.type === + CommunityTokenPermission_Type.BECOME_TOKEN_OWNER ) - // validate - if ( - !isClockValid( - BigInt(decodedCommunityDescription.clock), - message.timestamp - ) - ) { - return + if (!permission) { + continue } - // isSignatureValid - if (isEncrypted(decodedCommunityDescription.tokenPermissions)) { - // todo?: zod - const permission = Object.values( - decodedCommunityDescription.tokenPermissions - ).find( - permission => - permission.type === - CommunityTokenPermission_Type.BECOME_TOKEN_OWNER - ) + const criteria = permission.tokenCriteria[0] + const contracts = criteria?.contractAddresses + const chainId = Object.keys(contracts)[0] - if (!permission) { - return - } - - const criteria = permission.tokenCriteria[0] - const contracts = criteria?.contractAddresses - const chainId = Object.keys(contracts)[0] - - if (!chainId) { - return - } - - const ethereumClient = this.getEthereumClient(Number(chainId)) - - if (!ethereumClient) { - return - } - - const ownerPublicKey = await ethereumClient.resolveOwner( - this.#contractAddresses[Number(chainId)] - .CommunityOwnerTokenRegistry, - communityPublicKey - ) - - if (ownerPublicKey !== message.signerPublicKey) { - return - } - } else if ( - communityPublicKey !== - `0x${compressPublicKey(message.signerPublicKey)}` - ) { - return + if (!chainId) { + continue } - if (!communityDescription) { - communityDescription = decodedCommunityDescription + const providerUrl = this.#ethProviderURLs[Number(chainId)] + + if (!providerUrl) { + continue } - // stop - throw new Error('stop') + const ethereumClient = this.getEthereumClient(Number(chainId)) + + if (!ethereumClient) { + continue + } + + const ownerPublicKey = await ethereumClient.resolveOwner( + this.#contractAddresses[Number(chainId)] + .CommunityOwnerTokenRegistry, + communityPublicKey + ) + + if (ownerPublicKey !== message.signerPublicKey) { + continue + } + } else if ( + communityPublicKey !== + `0x${compressPublicKey(message.signerPublicKey)}` + ) { + continue } - ) - } catch { - // eslint-disable-next-line no-empty - } - return communityDescription + // stop + return decodedCommunityDescription + } + } } private fetchContactCodeAdvertisement = async ( @@ -313,67 +308,59 @@ class RequestClient { `${publicKey}-contact-code` ) - let contactCodeAdvertisement: ContactCodeAdvertisement | undefined = - undefined - try { - await this.waku.store.queryWithOrderedCallback( - [ - createDecoder(contentTopic, symmetricKey, { - clusterId: 16, - shard: 32, - }), - ], - wakuMessage => { - // handle - const message = this.handleWakuMessage(wakuMessage) - - if (!message) { - return - } - - if ( - message.type !== - ApplicationMetadataMessage_Type.CONTACT_CODE_ADVERTISEMENT - ) { - return - } - - // decode - const decodedContactCode = ContactCodeAdvertisement.fromBinary( - message.payload - ) - - // validate - if (!decodedContactCode.chatIdentity) { - return - } - - if ( - !isClockValid( - BigInt(decodedContactCode.chatIdentity.clock), - message.timestamp - ) - ) { - return - } - - if (publicKey !== message.signerPublicKey) { - return - } - - if (!contactCodeAdvertisement) { - contactCodeAdvertisement = decodedContactCode - } - - // stop - throw new Error('stop') + const wakuMessageGenerator = this.waku.store.queryGenerator([ + createDecoder(contentTopic, symmetricKey, { + clusterId: 16, + shard: 32, + }), + ]) + for await (const wakuMessages of wakuMessageGenerator) { + for await (const wakuMessage of wakuMessages) { + if (!wakuMessage) { + continue } - ) - } catch { - // eslint-disable-next-line no-empty - } - return contactCodeAdvertisement + // handle + const message = this.handleWakuMessage(wakuMessage) + + if (!message) { + continue + } + + if ( + message.type !== + ApplicationMetadataMessage_Type.CONTACT_CODE_ADVERTISEMENT + ) { + continue + } + + // decode + const decodedContactCode = ContactCodeAdvertisement.fromBinary( + message.payload + ) + + // validate + if (!decodedContactCode.chatIdentity) { + continue + } + + if ( + !isClockValid( + BigInt(decodedContactCode.chatIdentity.clock), + message.timestamp + ) + ) { + continue + } + + if (publicKey !== message.signerPublicKey) { + continue + } + + // stop + return decodedContactCode + } + } } private handleWakuMessage = (