Skip to content

Commit

Permalink
Added utils to help with debugging tx events
Browse files Browse the repository at this point in the history
  • Loading branch information
lukecaan committed Nov 27, 2024
1 parent fa407c8 commit b7c5b00
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 4 deletions.
77 changes: 77 additions & 0 deletions sdk/src/events/devOneShotLogProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
Connection,
PublicKey,
TransactionSignature,
} from '@solana/web3.js';
import { LogProvider, logProviderCallback } from './types';
import { oneShotFetchLogs } from './fetchLogs';

export class DevOneShotLogProvider implements LogProvider {
private callback?: logProviderCallback;
private _isSubscribed = false;

constructor(
private connection: Connection,
private address: PublicKey,
) {}

public async subscribe(
callback: logProviderCallback,
_skipHistory?: boolean
): Promise<boolean> {
if (this.isSubscribed()) {
return true;
}

this.callback = callback;
this._isSubscribed = true;
return true;
}

public async triggerLogs(txSig: TransactionSignature): Promise<void> {
if (!this.isSubscribed() || !this.callback) {
console.warn('DevOneShotLogProvider: Not subscribed or no callback registered');
return;
}

try {
// const response = await fetchLogs(
// this.connection,
// this.address,
// 'confirmed',
// undefined,
// txSig,
// 1
// );

const response = await oneShotFetchLogs(
this.connection,
this.address,
'confirmed',
txSig
);

if (!response || response.transactionLogs.length === 0) {
console.warn(`DevOneShotLogProvider: No logs found for tx ${txSig}`);
return;
}

for (const { txSig, slot, logs } of response.transactionLogs) {
this.callback(txSig, slot, logs, response.mostRecentBlockTime, undefined);
}
} catch (e) {
console.error('DevOneShotLogProvider: Error fetching logs');
console.error(e);
}
}

public isSubscribed(): boolean {
return this._isSubscribed;
}

public async unsubscribe(): Promise<boolean> {
this.callback = undefined;
this._isSubscribed = false;
return true;
}
}
7 changes: 5 additions & 2 deletions sdk/src/events/eventSubscriber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ import StrictEventEmitter from 'strict-event-emitter-types';
import { getSortFn } from './sort';
import { parseLogs } from './parse';
import { EventsServerLogProvider } from './eventsServerLogProvider';
import { DevOneShotLogProvider } from './devOneShotLogProvider';

export class EventSubscriber {
private address: PublicKey;
private eventListMap: Map<EventType, EventList<EventType>>;
private txEventCache: TxEventCache;
private awaitTxPromises = new Map<string, Promise<void>>();
private awaitTxResolver = new Map<string, () => void>();
private logProvider: LogProvider;
public logProvider: LogProvider;
private currentProviderType: LogProviderType;
public eventEmitter: StrictEventEmitter<EventEmitter, EventSubscriberEvents>;
private lastSeenSlot: number;
Expand All @@ -56,7 +57,9 @@ export class EventSubscriber {
private initializeLogProvider(subscribe = false) {
const logProviderConfig = this.options.logProviderConfig;

if (this.currentProviderType === 'websocket') {
if (this.currentProviderType === 'dev-one-shot') {
this.logProvider = new DevOneShotLogProvider(this.connection, this.address);
} else if (this.currentProviderType === 'websocket') {
this.logProvider = new WebSocketLogProvider(
// @ts-ignore
this.connection,
Expand Down
43 changes: 43 additions & 0 deletions sdk/src/events/fetchLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,3 +167,46 @@ export class LogParser {
return records;
}
}

export async function oneShotFetchLogs(
connection: Connection,
address: PublicKey,
finality: Finality,
txSig: TransactionSignature,
): Promise<{
transactionLogs: Log[];
mostRecentBlockTime: number | undefined;
} | undefined> {
try {
const signatures = await connection.getSignaturesForAddress(
address,
{
until: txSig,
limit: 1,
},
finality
);

if (signatures.length === 0) {
return undefined;
}

const transactionLogs = await fetchTransactionLogs(
connection,
[txSig],
finality
);

if (transactionLogs.length === 0) {
return undefined;
}

return {
transactionLogs,
mostRecentBlockTime: signatures[0].blockTime,
};
} catch (e) {
console.error('Error fetching logs:', e);
return undefined;
}
}
58 changes: 58 additions & 0 deletions sdk/src/events/getOneShotTxEvents.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Connection, PublicKey, TransactionSignature, Finality } from '@solana/web3.js';
import { Program } from '@coral-xyz/anchor';
import { WrappedEvents } from './types';
import { oneShotFetchLogs } from './fetchLogs';
import { parseLogs } from './parse';

/**
* Fetches and parses events for a single transaction signature
* @param connection Solana connection
* @param program Anchor program
* @param programId Program ID to fetch events for
* @param txSig Transaction signature to fetch events for
* @param commitment Finality commitment level
* @returns Promise containing array of parsed events, or undefined if transaction not found
*/
export async function getOneShotTxEvents(
connection: Connection,
program: Program,
programId: PublicKey,
txSig: TransactionSignature,
commitment: Finality = 'confirmed'
): Promise<WrappedEvents | undefined> {
try {
// Fetch the transaction logs
const response = await oneShotFetchLogs(
connection,
programId,
commitment,
txSig
);

if (!response || response.transactionLogs.length === 0) {
return undefined;
}

const txLog = response.transactionLogs[0];

// Parse the events
const events = parseLogs(program, txLog.logs);
const records: WrappedEvents = [];

let runningEventIndex = 0;
for (const event of events) {
event.data.txSig = txLog.txSig;
event.data.slot = txLog.slot;
event.data.eventType = event.name;
event.data.txSigIndex = runningEventIndex;
// @ts-ignore
records.push(event.data);
runningEventIndex++;
}

return records;
} catch (e) {
console.error(`Error fetching events for tx ${txSig}:`, e);
return undefined;
}
}
9 changes: 7 additions & 2 deletions sdk/src/events/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export interface LogProvider {
eventEmitter?: EventEmitter;
}

export type LogProviderType = 'websocket' | 'polling' | 'events-server';
export type LogProviderType = 'websocket' | 'polling' | 'events-server' | 'dev-one-shot';

export type StreamingLogProviderConfig = {
/// Max number of times to try reconnecting before failing over to fallback provider
Expand Down Expand Up @@ -179,7 +179,12 @@ export type EventsServerLogProviderConfig = StreamingLogProviderConfig & {
url: string;
};

export type DevOneShotLogProviderConfig = {
type: 'dev-one-shot';
};

export type LogProviderConfig =
| WebSocketLogProviderConfig
| PollingLogProviderConfig
| EventsServerLogProviderConfig;
| EventsServerLogProviderConfig
| DevOneShotLogProviderConfig;
2 changes: 2 additions & 0 deletions sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ export * from './events/txEventCache';
export * from './events/webSocketLogProvider';
export * from './events/parse';
export * from './events/pollingLogProvider';
export * from './events/getOneShotTxEvents';
export * from './events/devOneShotLogProvider';
export * from './jupiter/jupiterClient';
export * from './math/auction';
export * from './math/spotMarket';
Expand Down

0 comments on commit b7c5b00

Please sign in to comment.