Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Use BigInt JSON serialization in Solana RPC Subscriptions (#3455)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
lorisleiva authored Oct 27, 2024
1 parent 8f2ccc6 commit 500a991
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/orange-squids-think.md
Original file line number Diff line number Diff line change
@@ -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`.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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',
}),
});
Expand Down Expand Up @@ -712,7 +712,7 @@ Alternatively, you may explicitly create the RPC Subscriptions API using the `cr

```ts
import {
createDefaultRpcSubscriptionsChannelCreator,
createDefaultSolanaRpcSubscriptionsChannelCreator,
createDefaultRpcSubscriptionsTransport,
createSubscriptionRpc,
createSolanaRpcSubscriptionsApi,
Expand All @@ -723,7 +723,7 @@ import {

const api = createSolanaRpcSubscriptionsApi<AccountNotificationsApi & SlotNotificationsApi>(DEFAULT_RPC_CONFIG);
const transport = createDefaultRpcSubscriptionsTransport({
createChannel: createDefaultRpcSubscriptionsChannelCreator({
createChannel: createDefaultSolanaRpcSubscriptionsChannelCreator({
url: 'ws://127.0.0.1:8900',
}),
});
Expand Down
4 changes: 4 additions & 0 deletions packages/rpc-subscriptions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
24 changes: 23 additions & 1 deletion packages/rpc-subscriptions/src/rpc-subscriptions-channel.ts
Original file line number Diff line number Diff line change
@@ -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<TClusterUrl extends ClusterUrl> = Readonly<{
intervalMs?: number;
Expand All @@ -14,8 +16,28 @@ export type DefaultRpcSubscriptionsChannelConfig<TClusterUrl extends ClusterUrl>
url: TClusterUrl;
}>;

export function createDefaultSolanaRpcSubscriptionsChannelCreator<TClusterUrl extends ClusterUrl>(
config: DefaultRpcSubscriptionsChannelConfig<TClusterUrl>,
): RpcSubscriptionsChannelCreatorFromClusterUrl<TClusterUrl, unknown, unknown> {
return createDefaultRpcSubscriptionsChannelCreatorImpl({
...config,
jsonSerializer: getRpcSubscriptionsChannelWithBigIntJSONSerialization,
});
}

export function createDefaultRpcSubscriptionsChannelCreator<TClusterUrl extends ClusterUrl>(
config: DefaultRpcSubscriptionsChannelConfig<TClusterUrl>,
): RpcSubscriptionsChannelCreatorFromClusterUrl<TClusterUrl, unknown, unknown> {
return createDefaultRpcSubscriptionsChannelCreatorImpl({
...config,
jsonSerializer: getRpcSubscriptionsChannelWithJSONSerialization,
});
}

function createDefaultRpcSubscriptionsChannelCreatorImpl<TClusterUrl extends ClusterUrl>(
config: DefaultRpcSubscriptionsChannelConfig<TClusterUrl> & {
jsonSerializer: (channel: RpcSubscriptionsChannel<string, string>) => RpcSubscriptionsChannel<unknown, unknown>;
},
): RpcSubscriptionsChannelCreatorFromClusterUrl<TClusterUrl, unknown, unknown> {
if (/^wss?:/i.test(config.url) === false) {
const protocolMatch = config.url.match(/^([^:]+):/);
Expand All @@ -36,7 +58,7 @@ export function createDefaultRpcSubscriptionsChannelCreator<TClusterUrl extends
131_072,
signal: abortSignal,
})
.then(getRpcSubscriptionsChannelWithJSONSerialization)
.then(config.jsonSerializer)
.then(channel =>
getRpcSubscriptionsChannelWithAutoping({
abortSignal,
Expand Down
4 changes: 2 additions & 2 deletions packages/rpc-subscriptions/src/rpc-subscriptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -23,7 +23,7 @@ function createSolanaRpcSubscriptionsImpl<TClusterUrl extends ClusterUrl, TApi e
config?: Omit<DefaultRpcSubscriptionsConfig<TClusterUrl>, 'url'>,
) {
const transport = createDefaultRpcSubscriptionsTransport({
createChannel: createDefaultRpcSubscriptionsChannelCreator({ ...config, url: clusterUrl }),
createChannel: createDefaultSolanaRpcSubscriptionsChannelCreator({ ...config, url: clusterUrl }),
});
return createSolanaRpcSubscriptionsFromTransport<typeof transport, TApi>(transport);
}
Expand Down

0 comments on commit 500a991

Please sign in to comment.