57 lines
2.0 KiB
TypeScript
57 lines
2.0 KiB
TypeScript
import { Injectable, Logger } from '@nestjs/common';
|
||
import { ConfigService } from '@nestjs/config';
|
||
import Redis from 'ioredis';
|
||
|
||
@Injectable()
|
||
export class NonceManagerService {
|
||
private readonly logger = new Logger(NonceManagerService.name);
|
||
private redis: Redis;
|
||
|
||
constructor(private config: ConfigService) {
|
||
this.redis = new Redis(this.config.get('REDIS_URL') || 'redis://localhost:6379/2');
|
||
}
|
||
|
||
/** 获取并递增 Relayer 链上 nonce(Redis 原子操作,防 nonce 冲突) */
|
||
async next(relayerAddress: string): Promise<number> {
|
||
const key = `relayer:nonce:${relayerAddress}`;
|
||
const nonce = await this.redis.incr(key);
|
||
return nonce - 1; // incr returns value after increment
|
||
}
|
||
|
||
/** 初始化 nonce(从链上同步) */
|
||
async initialize(relayerAddress: string, chainNonce: number): Promise<void> {
|
||
const key = `relayer:nonce:${relayerAddress}`;
|
||
await this.redis.set(key, chainNonce);
|
||
this.logger.log(`Nonce initialized for ${relayerAddress}: ${chainNonce}`);
|
||
}
|
||
|
||
/** 检查用户 meta-tx nonce 是否已使用(防重放) */
|
||
async isNonceUsed(userAddress: string, nonce: number): Promise<boolean> {
|
||
const key = `user:nonce:${userAddress}`;
|
||
return (await this.redis.sismember(key, nonce.toString())) === 1;
|
||
}
|
||
|
||
/** 标记用户 nonce 已使用 */
|
||
async markNonceUsed(userAddress: string, nonce: number): Promise<void> {
|
||
const key = `user:nonce:${userAddress}`;
|
||
await this.redis.sadd(key, nonce.toString());
|
||
}
|
||
|
||
/** 获取用户每分钟请求计数(用于熔断) */
|
||
async getUserRateCount(userAddress: string): Promise<number> {
|
||
const key = `rate:${userAddress}`;
|
||
const count = await this.redis.get(key);
|
||
return parseInt(count || '0', 10);
|
||
}
|
||
|
||
/** 递增用户请求计数 */
|
||
async incrementUserRate(userAddress: string): Promise<number> {
|
||
const key = `rate:${userAddress}`;
|
||
const count = await this.redis.incr(key);
|
||
if (count === 1) {
|
||
await this.redis.expire(key, 60); // 60秒过期
|
||
}
|
||
return count;
|
||
}
|
||
}
|