From 500a991d292638eaee1fa48a7b94acfe2ff83cb7 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Sun, 27 Oct 2024 10:22:28 +0000 Subject: [PATCH] Use BigInt JSON serialization in Solana RPC Subscriptions (#3455) This PR offers a new `createDefaultSolanaRpcSubscriptionsChannelCreator` function that works similarly to `createDefaultRpcSubscriptionsChannelCreator` but with some Solana-specific defaults. Namely, it uses the brand new `getRpcSubscriptionsChannelWithBigIntJSONSerialization` function to stringify and parse messages to and from the server. --- .changeset/orange-squids-think.md | 5 ++++ README.md | 8 +++---- packages/rpc-subscriptions/README.md | 4 ++++ .../src/rpc-subscriptions-channel.ts | 24 ++++++++++++++++++- .../src/rpc-subscriptions.ts | 4 ++-- 5 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 .changeset/orange-squids-think.md diff --git a/.changeset/orange-squids-think.md b/.changeset/orange-squids-think.md new file mode 100644 index 000000000000..54b45cd25a03 --- /dev/null +++ b/.changeset/orange-squids-think.md @@ -0,0 +1,5 @@ +--- +'@solana/rpc-subscriptions': patch +--- + +Adds a channel creator function called `createDefaultSolanaRpcSubscriptionsChannelCreator`. This function works similarly to `createDefaultRpcSubscriptionsChannelCreator` but with some Solana-specific defaults. For instance, it safely handles `BigInt` values in JSON messages since Solana RPC servers accept and return integers larger than `Number.MAX_SAFE_INTEGER`. diff --git a/README.md b/README.md index be54bfe7adea..62ed93a858cc 100644 --- a/README.md +++ b/README.md @@ -671,7 +671,7 @@ If your app needs access to [unstable RPC Subscriptions](https://docs.solana.com ```ts import { - createDefaultRpcSubscriptionsChannelCreator, + createDefaultSolanaRpcSubscriptionsChannelCreator, createDefaultRpcSubscriptionsTransport, createSolanaRpcSubscriptions_UNSTABLE, createSolanaRpcSubscriptionsFromTransport_UNSTABLE, @@ -683,7 +683,7 @@ const rpcSubscriptions = createSolanaRpcSubscriptions_UNSTABLE('ws://127.0.0.1:8 // Using a custom transport. const transport = createDefaultRpcSubscriptionsTransport({ - createChannel: createDefaultRpcSubscriptionsChannelCreator({ + createChannel: createDefaultSolanaRpcSubscriptionsChannelCreator({ url: 'ws://127.0.0.1:8900', }), }); @@ -712,7 +712,7 @@ Alternatively, you may explicitly create the RPC Subscriptions API using the `cr ```ts import { - createDefaultRpcSubscriptionsChannelCreator, + createDefaultSolanaRpcSubscriptionsChannelCreator, createDefaultRpcSubscriptionsTransport, createSubscriptionRpc, createSolanaRpcSubscriptionsApi, @@ -723,7 +723,7 @@ import { const api = createSolanaRpcSubscriptionsApi(DEFAULT_RPC_CONFIG); const transport = createDefaultRpcSubscriptionsTransport({ - createChannel: createDefaultRpcSubscriptionsChannelCreator({ + createChannel: createDefaultSolanaRpcSubscriptionsChannelCreator({ url: 'ws://127.0.0.1:8900', }), }); diff --git a/packages/rpc-subscriptions/README.md b/packages/rpc-subscriptions/README.md index 53bc1b8714ac..d35a4584f39d 100644 --- a/packages/rpc-subscriptions/README.md +++ b/packages/rpc-subscriptions/README.md @@ -22,6 +22,10 @@ This package contains types that implement RPC subscriptions as required by the Creates a function that returns new subscription channels when called. +### `createDefaultSolanaRpcSubscriptionsChannelCreator(config)` + +Similar to `createDefaultRpcSubscriptionsChannelCreator` with some Solana-specific defaults. For instance, it safely handles `BigInt` values in JSON messages since Solana RPC servers accept and return integers larger than `Number.MAX_SAFE_INTEGER`. + #### Arguments A config object with the following properties: diff --git a/packages/rpc-subscriptions/src/rpc-subscriptions-channel.ts b/packages/rpc-subscriptions/src/rpc-subscriptions-channel.ts index 48cc5234efe1..364c0d1fee7b 100644 --- a/packages/rpc-subscriptions/src/rpc-subscriptions-channel.ts +++ b/packages/rpc-subscriptions/src/rpc-subscriptions-channel.ts @@ -1,10 +1,12 @@ import { createWebSocketChannel } from '@solana/rpc-subscriptions-channel-websocket'; +import type { RpcSubscriptionsChannel } from '@solana/rpc-subscriptions-spec'; import type { ClusterUrl } from '@solana/rpc-types'; import { getRpcSubscriptionsChannelWithAutoping } from './rpc-subscriptions-autopinger'; import { getChannelPoolingChannelCreator } from './rpc-subscriptions-channel-pool'; import { RpcSubscriptionsChannelCreatorFromClusterUrl } from './rpc-subscriptions-clusters'; import { getRpcSubscriptionsChannelWithJSONSerialization } from './rpc-subscriptions-json'; +import { getRpcSubscriptionsChannelWithBigIntJSONSerialization } from './rpc-subscriptions-json-bigint'; export type DefaultRpcSubscriptionsChannelConfig = Readonly<{ intervalMs?: number; @@ -14,8 +16,28 @@ export type DefaultRpcSubscriptionsChannelConfig url: TClusterUrl; }>; +export function createDefaultSolanaRpcSubscriptionsChannelCreator( + config: DefaultRpcSubscriptionsChannelConfig, +): RpcSubscriptionsChannelCreatorFromClusterUrl { + return createDefaultRpcSubscriptionsChannelCreatorImpl({ + ...config, + jsonSerializer: getRpcSubscriptionsChannelWithBigIntJSONSerialization, + }); +} + export function createDefaultRpcSubscriptionsChannelCreator( config: DefaultRpcSubscriptionsChannelConfig, +): RpcSubscriptionsChannelCreatorFromClusterUrl { + return createDefaultRpcSubscriptionsChannelCreatorImpl({ + ...config, + jsonSerializer: getRpcSubscriptionsChannelWithJSONSerialization, + }); +} + +function createDefaultRpcSubscriptionsChannelCreatorImpl( + config: DefaultRpcSubscriptionsChannelConfig & { + jsonSerializer: (channel: RpcSubscriptionsChannel) => RpcSubscriptionsChannel; + }, ): RpcSubscriptionsChannelCreatorFromClusterUrl { if (/^wss?:/i.test(config.url) === false) { const protocolMatch = config.url.match(/^([^:]+):/); @@ -36,7 +58,7 @@ export function createDefaultRpcSubscriptionsChannelCreator getRpcSubscriptionsChannelWithAutoping({ abortSignal, diff --git a/packages/rpc-subscriptions/src/rpc-subscriptions.ts b/packages/rpc-subscriptions/src/rpc-subscriptions.ts index f0b5660cd864..08ded9c39b60 100644 --- a/packages/rpc-subscriptions/src/rpc-subscriptions.ts +++ b/packages/rpc-subscriptions/src/rpc-subscriptions.ts @@ -9,7 +9,7 @@ import { ClusterUrl } from '@solana/rpc-types'; import { DEFAULT_RPC_SUBSCRIPTIONS_CONFIG } from './rpc-default-config'; import { - createDefaultRpcSubscriptionsChannelCreator, + createDefaultSolanaRpcSubscriptionsChannelCreator, DefaultRpcSubscriptionsChannelConfig, } from './rpc-subscriptions-channel'; import type { RpcSubscriptionsFromTransport } from './rpc-subscriptions-clusters'; @@ -23,7 +23,7 @@ function createSolanaRpcSubscriptionsImpl, 'url'>, ) { const transport = createDefaultRpcSubscriptionsTransport({ - createChannel: createDefaultRpcSubscriptionsChannelCreator({ ...config, url: clusterUrl }), + createChannel: createDefaultSolanaRpcSubscriptionsChannelCreator({ ...config, url: clusterUrl }), }); return createSolanaRpcSubscriptionsFromTransport(transport); }