fixing empty transaction

This commit is contained in:
2026-08-16 19:44:30 +00:00
parent a85647572a
commit 9e23b248e5
7 changed files with 357 additions and 63 deletions

View File

@@ -15,12 +15,14 @@ import { randomUUID } from 'crypto';
const mockOnLogs = vi.fn().mockReturnValue(12345);
const mockRemoveOnLogsListener = vi.fn().mockResolvedValue(true);
const mockGetTransaction = vi.fn();
const mockGetSignaturesForAddress = vi.fn().mockResolvedValue([]);
vi.mock('@solana/web3.js', () => {
class MockConnection {
onLogs = mockOnLogs;
removeOnLogsListener = mockRemoveOnLogsListener;
getTransaction = mockGetTransaction;
getSignaturesForAddress = mockGetSignaturesForAddress;
}
class MockPublicKey {
@@ -96,26 +98,17 @@ describe('Real Solana Observation Mode Unit Tests', () => {
// 2. RealWalletWatcher Subscription and Shutdown Behavior
describe('RealWalletWatcher Lifecycle & Reconnect Behavior', () => {
it('should subscribe to logs for all watched wallets on startup', async () => {
it('should query signatures on startup to set checkpoint and poll periodically', async () => {
const wallets = ['3yF9asA9B7G3Y1G7as78gHJKa7A', '4yF9asA9B7G3Y1G7as78gHJKa7B'];
mockGetSignaturesForAddress.mockResolvedValue([
{ signature: 'sig1', slot: 100, err: null }
]);
const watcher = new RealWalletWatcher(wallets, 'http://dummy-rpc', 'wss://dummy-wss');
await watcher.startWatching();
expect(connection.onLogs).toHaveBeenCalledTimes(2);
expect(connection.onLogs).toHaveBeenNthCalledWith(1, expect.any(Object), expect.any(Function), 'confirmed');
expect(connection.onLogs).toHaveBeenNthCalledWith(2, expect.any(Object), expect.any(Function), 'confirmed');
});
it('should unsubscribe from all logs listeners on shutdown', async () => {
const wallets = ['3yF9asA9B7G3Y1G7as78gHJKa7A'];
const watcher = new RealWalletWatcher(wallets, 'http://dummy-rpc', 'wss://dummy-wss');
await watcher.startWatching();
expect(mockGetSignaturesForAddress).toHaveBeenCalled();
await watcher.stopWatching();
expect(connection.removeOnLogsListener).toHaveBeenCalledTimes(1);
expect(connection.removeOnLogsListener).toHaveBeenCalledWith(12345);
});
});
@@ -327,6 +320,9 @@ describe('Real Solana Observation Mode Unit Tests', () => {
recordRpcRequestRate: vi.fn(),
recordQueueProcessed: vi.fn(),
recordRpcFetchError: vi.fn(),
recordWalletState: vi.fn(),
recordWalletIncomingRate: vi.fn(),
recordWalletProcessedRate: vi.fn(),
};
});
@@ -724,6 +720,75 @@ describe('Real Solana Observation Mode Unit Tests', () => {
loggerDebugSpy.mockRestore();
});
it('should correctly transition wallet state to HOT under overload and maintain NORMAL for others', async () => {
const { BoundedTransactionQueue } = await import('../src/solana/fetcher.js');
const queue = new BoundedTransactionQueue(
connection as any,
1, // maxConcurrency = 1
10, // minDelay = 10ms
5, // maxQueueSize = 5
mockMetrics,
);
queue.start();
// Push first item for walletA (goes active immediately)
queue.push({
signature: 'A1',
walletAddress: 'walletA',
slot: 100,
detectedAt: new Date(),
correlationId: 'corrA1',
onSuccess: async () => {},
onFailure: async () => {},
});
// walletA gets 4 more items queued (total depth 4/5 = 80%, should trigger HOT)
for (let i = 2; i <= 5; i++) {
queue.push({
signature: `A${i}`,
walletAddress: 'walletA',
slot: 100,
detectedAt: new Date(),
correlationId: `corrA${i}`,
onSuccess: async () => {},
onFailure: async () => {},
});
}
// walletB gets 1 item queued (depth 1/5, should stay NORMAL)
queue.push({
signature: 'B1',
walletAddress: 'walletB',
slot: 100,
detectedAt: new Date(),
correlationId: 'corrB1',
onSuccess: async () => {},
onFailure: async () => {},
});
expect(queue.getWalletState('walletA')).toBe('HOT');
expect(queue.getWalletState('walletB')).toBe('NORMAL');
queue.stop();
});
it('should pre-filter obviously irrelevant transactions using the lightweight log filter', async () => {
const { isLogIrrelevant } = await import('../src/solana/parser.js');
const irrelevantLogs = [
'Program Vote111111111111111111111111111111111111111 invoke [1]',
'Program Vote111111111111111111111111111111111111111 success',
];
const normalLogs = [
'Program ComputeBudget111111111111111111111111111111 invoke [1]',
'Program swapInstruction invoke [2]',
];
expect(isLogIrrelevant(irrelevantLogs)).toBe(true);
expect(isLogIrrelevant(normalLogs)).toBe(false);
});
it('should classify fetched transactions correctly based on SOL/SPL token balance changes', async () => {
const { isTransactionRelevant } = await import('../src/solana/parser.js');