Skip to content

Commit f9b0d6d

Browse files
authored
fix: onProgramAccountChange() and onAccountChange() now accept an encoding (#2861)
Fixes #2725.
1 parent 131900b commit f9b0d6d

File tree

2 files changed

+195
-6
lines changed

2 files changed

+195
-6
lines changed

packages/library-legacy/src/connection.ts

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2787,6 +2787,39 @@ export type GetNonceAndContextConfig = {
27872787
minContextSlot?: number;
27882788
};
27892789

2790+
export type AccountSubscriptionConfig = Readonly<{
2791+
/** Optional commitment level */
2792+
commitment?: Commitment;
2793+
/**
2794+
* Encoding format for Account data
2795+
* - `base58` is slow.
2796+
* - `jsonParsed` encoding attempts to use program-specific state parsers to return more
2797+
* human-readable and explicit account state data
2798+
* - If `jsonParsed` is requested but a parser cannot be found, the field falls back to `base64`
2799+
* encoding, detectable when the `data` field is type `string`.
2800+
*/
2801+
encoding?: 'base58' | 'base64' | 'base64+zstd' | 'jsonParsed';
2802+
}>;
2803+
2804+
export type ProgramAccountSubscriptionConfig = Readonly<{
2805+
/** Optional commitment level */
2806+
commitment?: Commitment;
2807+
/**
2808+
* Encoding format for Account data
2809+
* - `base58` is slow.
2810+
* - `jsonParsed` encoding attempts to use program-specific state parsers to return more
2811+
* human-readable and explicit account state data
2812+
* - If `jsonParsed` is requested but a parser cannot be found, the field falls back to `base64`
2813+
* encoding, detectable when the `data` field is type `string`.
2814+
*/
2815+
encoding?: 'base58' | 'base64' | 'base64+zstd' | 'jsonParsed';
2816+
/**
2817+
* Filter results using various filter objects
2818+
* The resultant account must meet ALL filter criteria to be included in the returned results
2819+
*/
2820+
filters?: GetProgramAccountsFilter[];
2821+
}>;
2822+
27902823
/**
27912824
* Information describing an account
27922825
*/
@@ -6334,18 +6367,34 @@ export class Connection {
63346367
*
63356368
* @param publicKey Public key of the account to monitor
63366369
* @param callback Function to invoke whenever the account is changed
6337-
* @param commitment Specify the commitment level account changes must reach before notification
6370+
* @param config
63386371
* @return subscription id
63396372
*/
6373+
onAccountChange(
6374+
publicKey: PublicKey,
6375+
callback: AccountChangeCallback,
6376+
config?: AccountSubscriptionConfig,
6377+
): ClientSubscriptionId;
6378+
/** @deprecated Instead, pass in an {@link AccountSubscriptionConfig} */
6379+
// eslint-disable-next-line no-dupe-class-members
63406380
onAccountChange(
63416381
publicKey: PublicKey,
63426382
callback: AccountChangeCallback,
63436383
commitment?: Commitment,
6384+
): ClientSubscriptionId;
6385+
// eslint-disable-next-line no-dupe-class-members
6386+
onAccountChange(
6387+
publicKey: PublicKey,
6388+
callback: AccountChangeCallback,
6389+
commitmentOrConfig?: Commitment | AccountSubscriptionConfig,
63446390
): ClientSubscriptionId {
6391+
const {commitment, config} =
6392+
extractCommitmentFromConfig(commitmentOrConfig);
63456393
const args = this._buildArgs(
63466394
[publicKey.toBase58()],
63476395
commitment || this._commitment || 'finalized', // Apply connection/server default.
63486396
'base64',
6397+
config,
63496398
);
63506399
return this._makeSubscription(
63516400
{
@@ -6394,21 +6443,40 @@ export class Connection {
63946443
*
63956444
* @param programId Public key of the program to monitor
63966445
* @param callback Function to invoke whenever the account is changed
6397-
* @param commitment Specify the commitment level account changes must reach before notification
6398-
* @param filters The program account filters to pass into the RPC method
6446+
* @param config
63996447
* @return subscription id
64006448
*/
6449+
onProgramAccountChange(
6450+
programId: PublicKey,
6451+
callback: ProgramAccountChangeCallback,
6452+
config?: ProgramAccountSubscriptionConfig,
6453+
): ClientSubscriptionId;
6454+
/** @deprecated Instead, pass in a {@link ProgramAccountSubscriptionConfig} */
6455+
// eslint-disable-next-line no-dupe-class-members
64016456
onProgramAccountChange(
64026457
programId: PublicKey,
64036458
callback: ProgramAccountChangeCallback,
64046459
commitment?: Commitment,
64056460
filters?: GetProgramAccountsFilter[],
6461+
): ClientSubscriptionId;
6462+
// eslint-disable-next-line no-dupe-class-members
6463+
onProgramAccountChange(
6464+
programId: PublicKey,
6465+
callback: ProgramAccountChangeCallback,
6466+
commitmentOrConfig?: Commitment | ProgramAccountSubscriptionConfig,
6467+
maybeFilters?: GetProgramAccountsFilter[],
64066468
): ClientSubscriptionId {
6469+
const {commitment, config} =
6470+
extractCommitmentFromConfig(commitmentOrConfig);
64076471
const args = this._buildArgs(
64086472
[programId.toBase58()],
64096473
commitment || this._commitment || 'finalized', // Apply connection/server default.
64106474
'base64' /* encoding */,
6411-
filters ? {filters: filters} : undefined /* extra */,
6475+
config
6476+
? config
6477+
: maybeFilters
6478+
? {filters: maybeFilters}
6479+
: undefined /* extra */,
64126480
);
64136481
return this._makeSubscription(
64146482
{

packages/library-legacy/test/connection.test.ts

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import {expect, use} from 'chai';
44
import chaiAsPromised from 'chai-as-promised';
55
import {Agent as HttpAgent} from 'http';
66
import {Agent as HttpsAgent} from 'https';
7-
import {match, mock, spy, useFakeTimers, SinonFakeTimers} from 'sinon';
7+
import {match, mock, spy, stub, useFakeTimers, SinonFakeTimers} from 'sinon';
88
import sinonChai from 'sinon-chai';
99
import {fail} from 'assert';
1010

@@ -5914,7 +5914,7 @@ describe('Connection', function () {
59145914
subscriptionId = connection.onAccountChange(
59155915
owner.publicKey,
59165916
resolve,
5917-
'confirmed',
5917+
{commitment: 'confirmed'},
59185918
);
59195919
},
59205920
);
@@ -6394,4 +6394,125 @@ describe('Connection', function () {
63946394
});
63956395
}).timeout(5 * 1000);
63966396
}
6397+
6398+
it('passes the commitment/encoding to the RPC when calling `onAccountChange`', () => {
6399+
const connection = new Connection(url);
6400+
const rpcRequestMethod = stub(
6401+
connection,
6402+
// @ts-expect-error This method is private, but none the less this spy will work.
6403+
'_makeSubscription',
6404+
);
6405+
const mockCallback = () => {};
6406+
connection.onAccountChange(PublicKey.default, mockCallback, {
6407+
commitment: 'processed',
6408+
encoding: 'base64+zstd',
6409+
});
6410+
expect(rpcRequestMethod).to.have.been.calledWithExactly(
6411+
{
6412+
callback: mockCallback,
6413+
method: 'accountSubscribe',
6414+
unsubscribeMethod: 'accountUnsubscribe',
6415+
},
6416+
[
6417+
match.any,
6418+
match
6419+
.has('commitment', 'processed')
6420+
.and(match.has('encoding', 'base64+zstd')),
6421+
],
6422+
);
6423+
});
6424+
it('passes the commitment to the RPC when the deprecated signature of `onAccountChange` is used', () => {
6425+
const connection = new Connection(url);
6426+
const rpcRequestMethod = stub(
6427+
connection,
6428+
// @ts-expect-error This method is private, but none the less this spy will work.
6429+
'_makeSubscription',
6430+
);
6431+
const mockCallback = () => {};
6432+
connection.onAccountChange(PublicKey.default, mockCallback, 'processed');
6433+
expect(rpcRequestMethod).to.have.been.calledWithExactly(
6434+
{
6435+
callback: mockCallback,
6436+
method: 'accountSubscribe',
6437+
unsubscribeMethod: 'accountUnsubscribe',
6438+
},
6439+
[match.any, match.has('commitment', 'processed')],
6440+
);
6441+
});
6442+
it('passes the commitment to the RPC when the deprecated signature of `onProgramAccountChange` is used', () => {
6443+
const connection = new Connection(url);
6444+
const rpcRequestMethod = stub(
6445+
connection,
6446+
// @ts-expect-error This method is private, but none the less this spy will work.
6447+
'_makeSubscription',
6448+
);
6449+
const mockCallback = () => {};
6450+
connection.onProgramAccountChange(
6451+
PublicKey.default,
6452+
mockCallback,
6453+
'processed' /* commitment */,
6454+
);
6455+
expect(rpcRequestMethod).to.have.been.calledWithExactly(
6456+
{
6457+
callback: mockCallback,
6458+
method: 'programSubscribe',
6459+
unsubscribeMethod: 'programUnsubscribe',
6460+
},
6461+
[match.any, match.has('commitment', 'processed')],
6462+
);
6463+
});
6464+
it('passes the filters to the RPC when the deprecated signature of `onProgramAccountChange` is used', () => {
6465+
const connection = new Connection(url);
6466+
const rpcRequestMethod = stub(
6467+
connection,
6468+
// @ts-expect-error This method is private, but none the less this spy will work.
6469+
'_makeSubscription',
6470+
);
6471+
const mockCallback = () => {};
6472+
connection.onProgramAccountChange(
6473+
PublicKey.default,
6474+
mockCallback,
6475+
/* commitment */ undefined,
6476+
/* filters */ [{dataSize: 123}],
6477+
);
6478+
expect(rpcRequestMethod).to.have.been.calledWithExactly(
6479+
{
6480+
callback: mockCallback,
6481+
method: 'programSubscribe',
6482+
unsubscribeMethod: 'programUnsubscribe',
6483+
},
6484+
[match.any, match.has('filters', [{dataSize: 123}])],
6485+
);
6486+
});
6487+
it('passes the commitment/encoding/filters to the RPC when calling `onProgramAccountChange`', () => {
6488+
const connection = new Connection(url);
6489+
const rpcRequestMethod = stub(
6490+
connection,
6491+
// @ts-expect-error This method is private, but none the less this spy will work.
6492+
'_makeSubscription',
6493+
);
6494+
const mockCallback = () => {};
6495+
connection.onProgramAccountChange(PublicKey.default, mockCallback, {
6496+
commitment: 'processed',
6497+
encoding: 'base64+zstd',
6498+
filters: [{dataSize: 123}],
6499+
});
6500+
expect(rpcRequestMethod).to.have.been.calledWithExactly(
6501+
{
6502+
callback: mockCallback,
6503+
method: 'programSubscribe',
6504+
unsubscribeMethod: 'programUnsubscribe',
6505+
},
6506+
[
6507+
match.any,
6508+
match
6509+
.has('commitment', 'processed')
6510+
.and(
6511+
match
6512+
.has('encoding', 'base64+zstd')
6513+
.and(match.has('filters', [{dataSize: 123}])),
6514+
),
6515+
],
6516+
);
6517+
});
63976518
});

0 commit comments

Comments
 (0)