Task 1-2: RPC Redundancy với Fallback Providers
Phase: 1 Priority: Medium Module:
solanaDepends on: Không có Reference: docs/bountyhunter-blockchain-p2/details/feature-solana-integration/SPEC.md
Background
Hiện tại SolanaUtil sử dụng một RPC endpoint duy nhất từ config — đây là single point of failure. Khi RPC provider downtime hoặc rate limit, toàn bộ Solana operations sẽ fail. Cần implement fallback RPC strategy: thử primary trước, nếu fail chuyển sang secondary, v.v. Pattern này phổ biến trong production Solana services và cần thiết cho high availability.
Tasks
Note:
Connectiontừ@solana/web3.jsphải được tạo với RPC URL cụ thể. Không thể thay đổi RPC của connection hiện tại — cần tạo connection mới cho mỗi RPC.SolanaUtilnên maintain array ofConnectionvà logic failover. ImportConnection,Commitmenttừ@solana/web3.js.
- [ ] Cập nhật
SolanaUtilconstructor để nhận array RPC URLs:export class SolanaUtil { private readonly connections: Connection[]; private currentConnectionIndex = 0; private readonly logger = new Logger(SolanaUtil.name); constructor(private readonly configService: ConfigService) { const rpcUrls = [ configService.get<string>('SOLANA_RPC_URL'), configService.get<string>('SOLANA_RPC_FALLBACK_1'), configService.get<string>('SOLANA_RPC_FALLBACK_2'), ].filter(Boolean) as string[]; this.connections = rpcUrls.map((url) => new Connection(url, 'confirmed')); this.logger.log(`[SOLANA] Initialized with ${this.connections.length} RPC endpoints`); } get connection(): Connection { return this.connections[this.currentConnectionIndex]; } } - [ ] Implement
failoverToNext()method:private failoverToNext(): boolean { if (this.currentConnectionIndex < this.connections.length - 1) { this.currentConnectionIndex++; this.logger.warn( `[SOLANA] RPC failover → switching to endpoint ${this.currentConnectionIndex + 1}/${this.connections.length}` ); return true; } return false; // No more fallbacks } - [ ] Tích hợp failover vào
sendWithRetry(task-1-1):// Khi lỗi là RPC error → thử failover if (isRpcError(error) && this.failoverToNext()) { continue; // retry với connection mới } - [ ] Thêm biến môi trường vào
.env.example:SOLANA_RPC_URL=https://api.mainnet-beta.solana.com SOLANA_RPC_FALLBACK_1=https://rpc.helius.xyz/?api-key=YOUR_KEY SOLANA_RPC_FALLBACK_2=https://solana-mainnet.g.alchemy.com/v2/YOUR_KEY - [ ] Reset
currentConnectionIndexsau khoảng thời gian (e.g., 5 phút) để thử lại primary:setTimeout(() => { this.currentConnectionIndex = 0; this.logger.log('[SOLANA] Reset to primary RPC endpoint'); }, 5 * 60 * 1000);
Verification / Acceptance Criteria
- [ ] Khi primary RPC trả lỗi connection → tự động switch sang
SOLANA_RPC_FALLBACK_1 - [ ] Khi cả primary và fallback 1 fail → switch sang
SOLANA_RPC_FALLBACK_2 - [ ] Sau 5 phút → reset về primary và thử lại
- [ ] Khi chỉ có
SOLANA_RPC_URL(không có fallback) → hoạt động bình thường (single endpoint) - [ ] Log rõ khi failover xảy ra với endpoint index
- [ ] TypeScript compile không có lỗi
Files to Modify
src/solana/utils/solana.util.ts.env.example