Skip to content

Commit 8a9773d

Browse files
authored
Merge pull request #2072 from drift-labs/revert-2071-revert-2070-jack/updated-triton-grpc
yellowstone-grpc:5.0.1
2 parents 47c2677 + fb492a8 commit 8a9773d

File tree

8 files changed

+365
-167
lines changed

8 files changed

+365
-167
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4242

4343
- program: isolated positions [#1757](https://github.com/drift-labs/protocol-v2/pull/1757)
4444
- program: delete serum/openbook configs [#2066](https://github.com/drift-labs/protocol-v2/pull/2066)
45+
- sdk: update yellowstone-grpc to rust client [#2070](https://github.com/drift-labs/protocol-v2/pull/2070)
4546

4647
### Fixes
4748

4849
### Breaking
50+
- sdk: `channelOptions` in the GrpcConfigs type has been updated to work with new grpc lib
4951

5052
## [2.153.0] - 2025-12-30
5153

sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"@solana/web3.js": "1.98.0",
5757
"@switchboard-xyz/common": "3.0.14",
5858
"@switchboard-xyz/on-demand": "2.4.1",
59-
"@triton-one/yellowstone-grpc": "1.4.1",
59+
"@triton-one/yellowstone-grpc": "5.0.2",
6060
"anchor-bankrun": "0.3.0",
6161
"gill": "^0.10.2",
6262
"nanoid": "3.3.4",

sdk/scripts/grpc-client-test-comparison.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,8 @@ async function initializeGrpcDriftClientV2VersusV1() {
9696
token: TOKEN,
9797
commitmentLevel: CommitmentLevel.PROCESSED,
9898
channelOptions: {
99-
'grpc.keepalive_time_ms': 10_000,
100-
'grpc.keepalive_timeout_ms': 1_000,
101-
'grpc.keepalive_permit_without_calls': 1,
99+
grpcKeepAliveTimeout: 1_000,
100+
grpcTcpKeepalive: 10_000,
102101
},
103102
},
104103
};

sdk/scripts/grpc-multiuser-client-test-comparison.ts

Lines changed: 140 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -13,144 +13,146 @@ const TOKEN = process.env.TOKEN;
1313
const RPC_ENDPOINT = process.env.RPC_ENDPOINT;
1414

1515
const USER_ACCOUNT_PUBKEYS = [
16-
// Add user account public keys here, e.g.:
17-
// new PublicKey('...')
16+
// Add user account public keys here, e.g.:
17+
// new PublicKey('...')
1818
];
1919

2020
async function testGrpcUserAccountSubscriberV1VsV2() {
21-
console.log('🚀 Initializing User Account Subscriber V1 vs V2 Test...');
22-
23-
if (USER_ACCOUNT_PUBKEYS.length === 0) {
24-
console.error('❌ No user account public keys provided. Please add some to USER_ACCOUNT_PUBKEYS array.');
25-
process.exit(1);
26-
}
27-
28-
const connection = new Connection(RPC_ENDPOINT);
29-
const wallet = new Wallet(new Keypair());
30-
31-
const programId = new PublicKey(DRIFT_PROGRAM_ID);
32-
const provider = new AnchorProvider(
33-
connection,
34-
// @ts-ignore
35-
wallet,
36-
{
37-
commitment: 'processed',
38-
}
39-
);
40-
41-
const program = new Program(driftIDL as Idl, programId, provider);
42-
43-
const grpcConfigs = {
44-
endpoint: GRPC_ENDPOINT,
45-
token: TOKEN,
46-
commitmentLevel: CommitmentLevel.PROCESSED,
47-
channelOptions: {
48-
'grpc.keepalive_time_ms': 10_000,
49-
'grpc.keepalive_timeout_ms': 1_000,
50-
'grpc.keepalive_permit_without_calls': 1,
51-
},
52-
};
53-
54-
console.log(`📊 Testing ${USER_ACCOUNT_PUBKEYS.length} user accounts...`);
55-
56-
// V1: Create individual subscribers for each user account
57-
const v1Subscribers = USER_ACCOUNT_PUBKEYS.map(
58-
(pubkey) =>
59-
new grpcUserAccountSubscriber(
60-
grpcConfigs,
61-
program,
62-
pubkey,
63-
{ logResubMessages: true }
64-
)
65-
);
66-
67-
// V2: Create a single multi-subscriber and get per-user interfaces
68-
const v2MultiSubscriber = new grpcMultiUserAccountSubscriber(
69-
program,
70-
grpcConfigs,
71-
{ logResubMessages: true }
72-
);
73-
const v2Subscribers = USER_ACCOUNT_PUBKEYS.map((pubkey) =>
74-
v2MultiSubscriber.forUser(pubkey)
75-
);
76-
77-
// Subscribe all V1 subscribers
78-
console.log('🔗 Subscribing V1 subscribers...');
79-
await Promise.all(v1Subscribers.map((sub) => sub.subscribe()));
80-
console.log('✅ V1 subscribers ready');
81-
82-
// Subscribe all V2 subscribers
83-
console.log('🔗 Subscribing V2 subscribers...');
84-
await v2MultiSubscriber.subscribe();
85-
console.log('✅ V2 subscribers ready');
86-
87-
const compare = () => {
88-
try {
89-
let passedTests = 0;
90-
let totalTests = 0;
91-
92-
// Test each user account
93-
for (let i = 0; i < USER_ACCOUNT_PUBKEYS.length; i++) {
94-
const pubkey = USER_ACCOUNT_PUBKEYS[i];
95-
const v1Sub = v1Subscribers[i];
96-
const v2Sub = v2Subscribers[i];
97-
98-
totalTests++;
99-
100-
// 1. Test isSubscribed
101-
assert.strictEqual(
102-
v1Sub.isSubscribed,
103-
v2Sub.isSubscribed,
104-
`User ${pubkey.toBase58()}: isSubscribed should match`
105-
);
106-
107-
// 2. Test getUserAccountAndSlot
108-
const v1Data = v1Sub.getUserAccountAndSlot();
109-
const v2Data = v2Sub.getUserAccountAndSlot();
110-
111-
// Compare the user account data
112-
assert.deepStrictEqual(
113-
v1Data.data,
114-
v2Data.data,
115-
`User ${pubkey.toBase58()}: account data should match`
116-
);
117-
118-
// Slots might differ slightly due to timing, but let's check if they're close
119-
const slotDiff = Math.abs(v1Data.slot - v2Data.slot);
120-
if (slotDiff > 10) {
121-
console.warn(
122-
`⚠️ User ${pubkey.toBase58()}: slot difference is ${slotDiff} (v1: ${v1Data.slot}, v2: ${v2Data.slot})`
123-
);
124-
}
125-
126-
passedTests++;
127-
}
128-
129-
console.log(`✅ All comparisons passed (${passedTests}/${totalTests} user accounts)`);
130-
} catch (error) {
131-
console.error('❌ Comparison failed:', error);
132-
}
133-
};
134-
135-
// Run initial comparison
136-
compare();
137-
138-
// Run comparison every second to verify live updates
139-
const interval = setInterval(compare, 1000);
140-
141-
const cleanup = async () => {
142-
clearInterval(interval);
143-
console.log('🧹 Cleaning up...');
144-
await Promise.all([
145-
...v1Subscribers.map((sub) => sub.unsubscribe()),
146-
...v2Subscribers.map((sub) => sub.unsubscribe()),
147-
]);
148-
console.log('✅ Cleanup complete');
149-
process.exit(0);
150-
};
151-
152-
process.on('SIGINT', cleanup);
153-
process.on('SIGTERM', cleanup);
154-
}
155-
156-
testGrpcUserAccountSubscriberV1VsV2().catch(console.error);
21+
console.log('🚀 Initializing User Account Subscriber V1 vs V2 Test...');
22+
23+
if (USER_ACCOUNT_PUBKEYS.length === 0) {
24+
console.error(
25+
'❌ No user account public keys provided. Please add some to USER_ACCOUNT_PUBKEYS array.'
26+
);
27+
process.exit(1);
28+
}
29+
30+
const connection = new Connection(RPC_ENDPOINT);
31+
const wallet = new Wallet(new Keypair());
32+
33+
const programId = new PublicKey(DRIFT_PROGRAM_ID);
34+
const provider = new AnchorProvider(
35+
connection,
36+
// @ts-ignore
37+
wallet,
38+
{
39+
commitment: 'processed',
40+
}
41+
);
42+
43+
const program = new Program(driftIDL as Idl, programId, provider);
44+
45+
const grpcConfigs = {
46+
endpoint: GRPC_ENDPOINT,
47+
token: TOKEN,
48+
commitmentLevel: CommitmentLevel.PROCESSED,
49+
channelOptions: {
50+
grpcKeepAliveTimeout: 1_000,
51+
grpcTcpKeepalive: 10_000,
52+
},
53+
};
54+
55+
console.log(`📊 Testing ${USER_ACCOUNT_PUBKEYS.length} user accounts...`);
56+
57+
// V1: Create individual subscribers for each user account
58+
const v1Subscribers = USER_ACCOUNT_PUBKEYS.map(
59+
(pubkey) =>
60+
new grpcUserAccountSubscriber(grpcConfigs, program, pubkey, {
61+
logResubMessages: true,
62+
})
63+
);
64+
65+
// V2: Create a single multi-subscriber and get per-user interfaces
66+
const v2MultiSubscriber = new grpcMultiUserAccountSubscriber(
67+
program,
68+
grpcConfigs,
69+
{ logResubMessages: true }
70+
);
71+
const v2Subscribers = USER_ACCOUNT_PUBKEYS.map((pubkey) =>
72+
v2MultiSubscriber.forUser(pubkey)
73+
);
74+
75+
// Subscribe all V1 subscribers
76+
console.log('🔗 Subscribing V1 subscribers...');
77+
await Promise.all(v1Subscribers.map((sub) => sub.subscribe()));
78+
console.log('✅ V1 subscribers ready');
79+
80+
// Subscribe all V2 subscribers
81+
console.log('🔗 Subscribing V2 subscribers...');
82+
await v2MultiSubscriber.subscribe();
83+
console.log('✅ V2 subscribers ready');
84+
85+
const compare = () => {
86+
try {
87+
let passedTests = 0;
88+
let totalTests = 0;
89+
90+
// Test each user account
91+
for (let i = 0; i < USER_ACCOUNT_PUBKEYS.length; i++) {
92+
const pubkey = USER_ACCOUNT_PUBKEYS[i];
93+
const v1Sub = v1Subscribers[i];
94+
const v2Sub = v2Subscribers[i];
95+
96+
totalTests++;
97+
98+
// 1. Test isSubscribed
99+
assert.strictEqual(
100+
v1Sub.isSubscribed,
101+
v2Sub.isSubscribed,
102+
`User ${pubkey.toBase58()}: isSubscribed should match`
103+
);
104+
105+
// 2. Test getUserAccountAndSlot
106+
const v1Data = v1Sub.getUserAccountAndSlot();
107+
const v2Data = v2Sub.getUserAccountAndSlot();
108+
109+
// Compare the user account data
110+
assert.deepStrictEqual(
111+
v1Data.data,
112+
v2Data.data,
113+
`User ${pubkey.toBase58()}: account data should match`
114+
);
115+
116+
// Slots might differ slightly due to timing, but let's check if they're close
117+
const slotDiff = Math.abs(v1Data.slot - v2Data.slot);
118+
if (slotDiff > 10) {
119+
console.warn(
120+
`⚠️ User ${pubkey.toBase58()}: slot difference is ${slotDiff} (v1: ${
121+
v1Data.slot
122+
}, v2: ${v2Data.slot})`
123+
);
124+
}
125+
126+
passedTests++;
127+
}
128+
129+
console.log(
130+
`✅ All comparisons passed (${passedTests}/${totalTests} user accounts)`
131+
);
132+
} catch (error) {
133+
console.error('❌ Comparison failed:', error);
134+
}
135+
};
136+
137+
// Run initial comparison
138+
compare();
139+
140+
// Run comparison every second to verify live updates
141+
const interval = setInterval(compare, 1000);
142+
143+
const cleanup = async () => {
144+
clearInterval(interval);
145+
console.log('🧹 Cleaning up...');
146+
await Promise.all([
147+
...v1Subscribers.map((sub) => sub.unsubscribe()),
148+
...v2Subscribers.map((sub) => sub.unsubscribe()),
149+
]);
150+
console.log('✅ Cleanup complete');
151+
process.exit(0);
152+
};
153+
154+
process.on('SIGINT', cleanup);
155+
process.on('SIGTERM', cleanup);
156+
}
157+
158+
testGrpcUserAccountSubscriberV1VsV2().catch(console.error);

sdk/scripts/single-grpc-client-test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,13 @@ async function initializeSingleGrpcClient() {
9797
);
9898
console.log(`🔮 Oracles: ${oracleInfos.length}`);
9999

100-
101100
const grpcConfigs = {
102101
endpoint: GRPC_ENDPOINT,
103102
token: TOKEN,
104103
commitmentLevel: CommitmentLevel.PROCESSED,
105104
channelOptions: {
106-
'grpc.keepalive_time_ms': 10_000,
107-
'grpc.keepalive_timeout_ms': 1_000,
108-
'grpc.keepalive_permit_without_calls': 1,
105+
grpcKeepAliveTimeout: 1_000,
106+
grpcTcpKeepalive: 10_000,
109107
},
110108
};
111109

sdk/src/accounts/laserProgramAccountSubscriber.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { GrpcConfigs, ResubOpts } from './types';
1+
import { LaserGrpcConfigs, ResubOpts } from './types';
22
import { Program } from '@coral-xyz/anchor';
33
import { Context, MemcmpFilter, PublicKey } from '@solana/web3.js';
44
import * as Buffer from 'buffer';
@@ -60,7 +60,7 @@ export class LaserstreamProgramAccountSubscriber<
6060
}
6161

6262
public static async create<U>(
63-
grpcConfigs: GrpcConfigs,
63+
grpcConfigs: LaserGrpcConfigs,
6464
subscriptionName: string,
6565
accountDiscriminator: string,
6666
program: Program,

sdk/src/accounts/types.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { Context, PublicKey } from '@solana/web3.js';
1515
import { Account } from '@solana/spl-token';
1616
import { OracleInfo, OraclePriceData } from '../oracles/types';
1717
import { User } from '../user';
18-
import { ChannelOptions, CommitmentLevel } from '../isomorphic/grpc';
18+
import { Client, CommitmentLevel, LaserstreamConfig } from '../isomorphic/grpc';
1919

2020
export interface AccountSubscriber<T> {
2121
dataAndSlot?: DataAndSlot<T>;
@@ -225,19 +225,29 @@ export interface UserStatsAccountSubscriber {
225225
getUserStatsAccountAndSlot(): DataAndSlot<UserStatsAccount>;
226226
}
227227

228-
export type GrpcConfigs = {
228+
type BaseGrpcConfigs = {
229229
endpoint: string;
230230
token: string;
231231
commitmentLevel?: CommitmentLevel;
232-
channelOptions?: ChannelOptions;
233232
/**
234233
* Whether to enable automatic reconnection on connection loss .
235234
* Defaults to false, will throw on connection loss.
236235
*/
237236
enableReconnect?: boolean;
238-
client?: 'yellowstone' | 'laser';
239237
};
240238

239+
export type YellowstoneGrpcConfigs = BaseGrpcConfigs & {
240+
client?: 'yellowstone';
241+
channelOptions?: ConstructorParameters<typeof Client>[2];
242+
};
243+
244+
export type LaserGrpcConfigs = BaseGrpcConfigs & {
245+
client: 'laser';
246+
channelOptions?: LaserstreamConfig['channelOptions'];
247+
};
248+
249+
export type GrpcConfigs = YellowstoneGrpcConfigs | LaserGrpcConfigs;
250+
241251
export interface HighLeverageModeConfigAccountSubscriber {
242252
eventEmitter: StrictEventEmitter<
243253
EventEmitter,

0 commit comments

Comments
 (0)