@f2a/network 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -1
- package/.github/workflows/ci.yml +0 -113
- package/.github/workflows/publish.yml +0 -60
- package/MONOREPO.md +0 -58
- package/SKILL.md +0 -137
- package/dist/adapters/openclaw.d.ts +0 -103
- package/dist/adapters/openclaw.d.ts.map +0 -1
- package/dist/adapters/openclaw.js +0 -297
- package/dist/adapters/openclaw.js.map +0 -1
- package/dist/core/connection-manager.d.ts +0 -80
- package/dist/core/connection-manager.d.ts.map +0 -1
- package/dist/core/connection-manager.js +0 -235
- package/dist/core/connection-manager.js.map +0 -1
- package/dist/core/connection-manager.test.d.ts +0 -2
- package/dist/core/connection-manager.test.d.ts.map +0 -1
- package/dist/core/connection-manager.test.js +0 -52
- package/dist/core/connection-manager.test.js.map +0 -1
- package/dist/core/identity.d.ts +0 -47
- package/dist/core/identity.d.ts.map +0 -1
- package/dist/core/identity.js +0 -130
- package/dist/core/identity.js.map +0 -1
- package/dist/core/identity.test.d.ts +0 -2
- package/dist/core/identity.test.d.ts.map +0 -1
- package/dist/core/identity.test.js +0 -43
- package/dist/core/identity.test.js.map +0 -1
- package/dist/core/serverless.d.ts +0 -155
- package/dist/core/serverless.d.ts.map +0 -1
- package/dist/core/serverless.js +0 -615
- package/dist/core/serverless.js.map +0 -1
- package/dist/daemon/webhook.test.d.ts +0 -2
- package/dist/daemon/webhook.test.d.ts.map +0 -1
- package/dist/daemon/webhook.test.js +0 -24
- package/dist/daemon/webhook.test.js.map +0 -1
- package/dist/protocol/messages.d.ts +0 -739
- package/dist/protocol/messages.d.ts.map +0 -1
- package/dist/protocol/messages.js +0 -188
- package/dist/protocol/messages.js.map +0 -1
- package/dist/protocol/messages.test.d.ts +0 -2
- package/dist/protocol/messages.test.d.ts.map +0 -1
- package/dist/protocol/messages.test.js +0 -55
- package/dist/protocol/messages.test.js.map +0 -1
- package/docs/F2A-PROTOCOL.md +0 -61
- package/docs/MOBILE_BOOTSTRAP_DESIGN.md +0 -126
- package/docs/a2a-lessons.md +0 -316
- package/docs/middleware-guide.md +0 -448
- package/docs/readme-update-checklist.md +0 -90
- package/docs/reputation-guide.md +0 -396
- package/docs/rfcs/001-reputation-system.md +0 -712
- package/docs/security-design.md +0 -247
- package/install.sh +0 -231
- package/packages/openclaw-adapter/README.md +0 -510
- package/packages/openclaw-adapter/openclaw.plugin.json +0 -106
- package/packages/openclaw-adapter/package.json +0 -40
- package/packages/openclaw-adapter/src/announcement-queue.test.ts +0 -449
- package/packages/openclaw-adapter/src/announcement-queue.ts +0 -403
- package/packages/openclaw-adapter/src/capability-detector.test.ts +0 -99
- package/packages/openclaw-adapter/src/capability-detector.ts +0 -183
- package/packages/openclaw-adapter/src/claim-handlers.test.ts +0 -974
- package/packages/openclaw-adapter/src/claim-handlers.ts +0 -482
- package/packages/openclaw-adapter/src/connector.business.test.ts +0 -583
- package/packages/openclaw-adapter/src/connector.ts +0 -795
- package/packages/openclaw-adapter/src/index.test.ts +0 -82
- package/packages/openclaw-adapter/src/index.ts +0 -18
- package/packages/openclaw-adapter/src/integration.e2e.test.ts +0 -829
- package/packages/openclaw-adapter/src/logger.ts +0 -51
- package/packages/openclaw-adapter/src/network-client.test.ts +0 -266
- package/packages/openclaw-adapter/src/network-client.ts +0 -251
- package/packages/openclaw-adapter/src/network-recovery.test.ts +0 -465
- package/packages/openclaw-adapter/src/node-manager.test.ts +0 -136
- package/packages/openclaw-adapter/src/node-manager.ts +0 -429
- package/packages/openclaw-adapter/src/plugin.test.ts +0 -439
- package/packages/openclaw-adapter/src/plugin.ts +0 -104
- package/packages/openclaw-adapter/src/reputation.test.ts +0 -221
- package/packages/openclaw-adapter/src/reputation.ts +0 -368
- package/packages/openclaw-adapter/src/task-guard.test.ts +0 -502
- package/packages/openclaw-adapter/src/task-guard.ts +0 -860
- package/packages/openclaw-adapter/src/task-queue.concurrency.test.ts +0 -462
- package/packages/openclaw-adapter/src/task-queue.edge-cases.test.ts +0 -284
- package/packages/openclaw-adapter/src/task-queue.persistence.test.ts +0 -408
- package/packages/openclaw-adapter/src/task-queue.ts +0 -668
- package/packages/openclaw-adapter/src/tool-handlers.test.ts +0 -906
- package/packages/openclaw-adapter/src/tool-handlers.ts +0 -574
- package/packages/openclaw-adapter/src/types.ts +0 -361
- package/packages/openclaw-adapter/src/webhook-pusher.test.ts +0 -188
- package/packages/openclaw-adapter/src/webhook-pusher.ts +0 -220
- package/packages/openclaw-adapter/src/webhook-server.test.ts +0 -580
- package/packages/openclaw-adapter/src/webhook-server.ts +0 -202
- package/packages/openclaw-adapter/tsconfig.json +0 -20
- package/src/cli/commands.test.ts +0 -157
- package/src/cli/commands.ts +0 -129
- package/src/cli/index.test.ts +0 -77
- package/src/cli/index.ts +0 -234
- package/src/core/autonomous-economy.test.ts +0 -291
- package/src/core/autonomous-economy.ts +0 -428
- package/src/core/e2ee-crypto.test.ts +0 -125
- package/src/core/e2ee-crypto.ts +0 -246
- package/src/core/f2a.test.ts +0 -269
- package/src/core/f2a.ts +0 -618
- package/src/core/p2p-network.test.ts +0 -199
- package/src/core/p2p-network.ts +0 -1432
- package/src/core/reputation-security.test.ts +0 -403
- package/src/core/reputation-security.ts +0 -562
- package/src/core/reputation.test.ts +0 -260
- package/src/core/reputation.ts +0 -576
- package/src/core/review-committee.test.ts +0 -380
- package/src/core/review-committee.ts +0 -401
- package/src/core/token-manager.test.ts +0 -133
- package/src/core/token-manager.ts +0 -140
- package/src/daemon/control-server.test.ts +0 -216
- package/src/daemon/control-server.ts +0 -292
- package/src/daemon/index.test.ts +0 -85
- package/src/daemon/index.ts +0 -89
- package/src/daemon/main.ts +0 -44
- package/src/daemon/start.ts +0 -29
- package/src/daemon/webhook.test.ts +0 -68
- package/src/daemon/webhook.ts +0 -105
- package/src/index.test.ts +0 -436
- package/src/index.ts +0 -72
- package/src/types/index.test.ts +0 -87
- package/src/types/index.ts +0 -341
- package/src/types/result.ts +0 -68
- package/src/utils/benchmark.ts +0 -237
- package/src/utils/logger.ts +0 -331
- package/src/utils/middleware.ts +0 -229
- package/src/utils/rate-limiter.ts +0 -207
- package/src/utils/signature.ts +0 -136
- package/src/utils/validation.ts +0 -186
- package/tests/docker/Dockerfile.node +0 -23
- package/tests/docker/Dockerfile.runner +0 -18
- package/tests/docker/docker-compose.test.yml +0 -73
- package/tests/integration/message-passing.test.ts +0 -109
- package/tests/integration/multi-node.test.ts +0 -92
- package/tests/integration/p2p-connection.test.ts +0 -83
- package/tests/integration/test-config.ts +0 -32
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -26
package/src/core/reputation.ts
DELETED
|
@@ -1,576 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* F2A 信誉系统
|
|
3
|
-
* Phase 1: 基础信誉管理
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Logger } from '../utils/logger.js';
|
|
7
|
-
|
|
8
|
-
// ============================================================================
|
|
9
|
-
// 类型定义
|
|
10
|
-
// ============================================================================
|
|
11
|
-
|
|
12
|
-
export type ReputationLevel = 'restricted' | 'novice' | 'participant' | 'contributor' | 'core';
|
|
13
|
-
|
|
14
|
-
export interface ReputationTier {
|
|
15
|
-
min: number;
|
|
16
|
-
max: number;
|
|
17
|
-
level: ReputationLevel;
|
|
18
|
-
title: string;
|
|
19
|
-
permissions: {
|
|
20
|
-
canPublish: boolean;
|
|
21
|
-
canExecute: boolean;
|
|
22
|
-
canReview: boolean;
|
|
23
|
-
publishPriority: number;
|
|
24
|
-
publishDiscount: number;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export interface ReputationEntry {
|
|
29
|
-
peerId: string;
|
|
30
|
-
score: number;
|
|
31
|
-
level: ReputationLevel;
|
|
32
|
-
lastUpdated: number;
|
|
33
|
-
history: ReputationEvent[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface ReputationEvent {
|
|
37
|
-
type: 'task_success' | 'task_failure' | 'task_rejected' | 'review_given' | 'review_penalty' | 'initial';
|
|
38
|
-
delta: number;
|
|
39
|
-
timestamp: number;
|
|
40
|
-
reason?: string;
|
|
41
|
-
taskId?: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface ReputationConfig {
|
|
45
|
-
initialScore: number;
|
|
46
|
-
alpha: number; // EWMA 平滑系数
|
|
47
|
-
minScore: number;
|
|
48
|
-
maxScore: number;
|
|
49
|
-
maxHistory: number; // 历史记录上限
|
|
50
|
-
decayRate: number; // 衰减率(每日衰减百分比,如 0.01 表示每天衰减 1%)
|
|
51
|
-
decayIntervalMs: number; // 衰减检查间隔(毫秒)
|
|
52
|
-
maxLatency: number; // 最大可接受的延迟(毫秒)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ============================================================================
|
|
56
|
-
// 持久化接口
|
|
57
|
-
// ============================================================================
|
|
58
|
-
|
|
59
|
-
export interface ReputationStorage {
|
|
60
|
-
save(entries: Map<string, ReputationEntry>): Promise<void>;
|
|
61
|
-
load(): Promise<Map<string, ReputationEntry>>;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// ============================================================================
|
|
65
|
-
// 信誉等级定义
|
|
66
|
-
// ============================================================================
|
|
67
|
-
|
|
68
|
-
export const REPUTATION_TIERS: ReputationTier[] = [
|
|
69
|
-
{
|
|
70
|
-
min: 0,
|
|
71
|
-
max: 20,
|
|
72
|
-
level: 'restricted',
|
|
73
|
-
title: '受限者',
|
|
74
|
-
permissions: {
|
|
75
|
-
canPublish: false,
|
|
76
|
-
canExecute: true,
|
|
77
|
-
canReview: false,
|
|
78
|
-
publishPriority: 0,
|
|
79
|
-
publishDiscount: 1.0,
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
min: 20,
|
|
84
|
-
max: 40,
|
|
85
|
-
level: 'novice',
|
|
86
|
-
title: '新手',
|
|
87
|
-
permissions: {
|
|
88
|
-
canPublish: true,
|
|
89
|
-
canExecute: true,
|
|
90
|
-
canReview: false,
|
|
91
|
-
publishPriority: 1,
|
|
92
|
-
publishDiscount: 1.0,
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
min: 40,
|
|
97
|
-
max: 60,
|
|
98
|
-
level: 'participant',
|
|
99
|
-
title: '参与者',
|
|
100
|
-
permissions: {
|
|
101
|
-
canPublish: true,
|
|
102
|
-
canExecute: true,
|
|
103
|
-
canReview: true,
|
|
104
|
-
publishPriority: 2,
|
|
105
|
-
publishDiscount: 1.0,
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
min: 60,
|
|
110
|
-
max: 80,
|
|
111
|
-
level: 'contributor',
|
|
112
|
-
title: '贡献者',
|
|
113
|
-
permissions: {
|
|
114
|
-
canPublish: true,
|
|
115
|
-
canExecute: true,
|
|
116
|
-
canReview: true,
|
|
117
|
-
publishPriority: 3,
|
|
118
|
-
publishDiscount: 0.9,
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
min: 80,
|
|
123
|
-
max: 100,
|
|
124
|
-
level: 'core',
|
|
125
|
-
title: '核心成员',
|
|
126
|
-
permissions: {
|
|
127
|
-
canPublish: true,
|
|
128
|
-
canExecute: true,
|
|
129
|
-
canReview: true,
|
|
130
|
-
publishPriority: 5,
|
|
131
|
-
publishDiscount: 0.7,
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
];
|
|
135
|
-
|
|
136
|
-
// ============================================================================
|
|
137
|
-
// 默认配置
|
|
138
|
-
// ============================================================================
|
|
139
|
-
|
|
140
|
-
const DEFAULT_CONFIG: ReputationConfig = {
|
|
141
|
-
initialScore: 70,
|
|
142
|
-
alpha: 0.3,
|
|
143
|
-
minScore: 0,
|
|
144
|
-
maxScore: 100,
|
|
145
|
-
maxHistory: 100,
|
|
146
|
-
decayRate: 0.01, // 每天衰减 1%
|
|
147
|
-
decayIntervalMs: 24 * 60 * 60 * 1000, // 每 24 小时检查一次
|
|
148
|
-
maxLatency: 300000, // 最大可接受延迟 5 分钟
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
// ============================================================================
|
|
152
|
-
// 信誉管理器
|
|
153
|
-
// ============================================================================
|
|
154
|
-
|
|
155
|
-
export class ReputationManager implements Disposable {
|
|
156
|
-
private config: ReputationConfig;
|
|
157
|
-
private entries: Map<string, ReputationEntry> = new Map();
|
|
158
|
-
private logger: Logger;
|
|
159
|
-
private decayTimer?: NodeJS.Timeout;
|
|
160
|
-
private disposed: boolean = false;
|
|
161
|
-
|
|
162
|
-
constructor(config: Partial<ReputationConfig> = {}) {
|
|
163
|
-
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
164
|
-
this.logger = new Logger({ component: 'Reputation' });
|
|
165
|
-
|
|
166
|
-
// 启动衰减定时器
|
|
167
|
-
if (this.config.decayRate > 0) {
|
|
168
|
-
this.startDecayTimer();
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* 实现 Disposable 接口
|
|
174
|
-
*/
|
|
175
|
-
[Symbol.dispose](): void {
|
|
176
|
-
this.stop();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* 停止定时器和清理资源
|
|
181
|
-
*/
|
|
182
|
-
stop(): void {
|
|
183
|
-
if (this.disposed) return;
|
|
184
|
-
this.disposed = true;
|
|
185
|
-
|
|
186
|
-
if (this.decayTimer) {
|
|
187
|
-
clearInterval(this.decayTimer);
|
|
188
|
-
this.decayTimer = undefined;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* 启动衰减定时器
|
|
194
|
-
*/
|
|
195
|
-
private startDecayTimer(): void {
|
|
196
|
-
this.decayTimer = setInterval(() => {
|
|
197
|
-
this.applyDecay();
|
|
198
|
-
}, this.config.decayIntervalMs);
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* 应用信誉衰减
|
|
203
|
-
* 每个节点的信誉分数按 decayRate 比例衰减
|
|
204
|
-
*/
|
|
205
|
-
private applyDecay(): void {
|
|
206
|
-
const decayFactor = 1 - this.config.decayRate;
|
|
207
|
-
|
|
208
|
-
for (const [peerId, entry] of this.entries) {
|
|
209
|
-
// 不衰减初始分数以下的值
|
|
210
|
-
if (entry.score > this.config.initialScore) {
|
|
211
|
-
const newScore = entry.score * decayFactor;
|
|
212
|
-
// 确保不低于初始分数
|
|
213
|
-
entry.score = Math.max(this.config.initialScore, newScore);
|
|
214
|
-
entry.level = this.getTier(entry.score).level;
|
|
215
|
-
entry.lastUpdated = Date.now();
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
this.logger.debug('Applied reputation decay', {
|
|
220
|
-
decayRate: this.config.decayRate,
|
|
221
|
-
entriesAffected: this.entries.size
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* 获取节点信誉信息
|
|
227
|
-
* 如果节点不存在,会自动创建一个带有初始分数的条目
|
|
228
|
-
* @param peerId - 节点的唯一标识符
|
|
229
|
-
* @returns 节点的信誉条目,包含分数、等级和历史记录
|
|
230
|
-
*/
|
|
231
|
-
getReputation(peerId: string): ReputationEntry {
|
|
232
|
-
if (!this.entries.has(peerId)) {
|
|
233
|
-
this.entries.set(peerId, this.createInitialEntry(peerId));
|
|
234
|
-
}
|
|
235
|
-
return this.entries.get(peerId)!;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* 获取信誉等级信息
|
|
240
|
-
* 根据分数返回对应的信誉等级和权限配置
|
|
241
|
-
* @param score - 信誉分数 (0-100)
|
|
242
|
-
* @returns 对应的信誉等级配置
|
|
243
|
-
*/
|
|
244
|
-
getTier(score: number): ReputationTier {
|
|
245
|
-
for (const tier of REPUTATION_TIERS) {
|
|
246
|
-
if (score >= tier.min && score < tier.max) {
|
|
247
|
-
return tier;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
return REPUTATION_TIERS[REPUTATION_TIERS.length - 1]; // core
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* 检查节点是否具有指定权限
|
|
255
|
-
* @param peerId - 节点的唯一标识符
|
|
256
|
-
* @param permission - 要检查的权限类型:'publish'(发布)、'execute'(执行)、'review'(评审)
|
|
257
|
-
* @returns 如果节点具有该权限则返回 true,否则返回 false
|
|
258
|
-
*/
|
|
259
|
-
hasPermission(peerId: string, permission: 'publish' | 'execute' | 'review'): boolean {
|
|
260
|
-
const entry = this.getReputation(peerId);
|
|
261
|
-
const tier = this.getTier(entry.score);
|
|
262
|
-
|
|
263
|
-
switch (permission) {
|
|
264
|
-
case 'publish':
|
|
265
|
-
return tier.permissions.canPublish;
|
|
266
|
-
case 'execute':
|
|
267
|
-
return tier.permissions.canExecute;
|
|
268
|
-
case 'review':
|
|
269
|
-
return tier.permissions.canReview;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* 记录任务成功
|
|
275
|
-
* @param peerId 节点 ID
|
|
276
|
-
* @param taskId 任务 ID
|
|
277
|
-
* @param delta 分数变化量
|
|
278
|
-
* @param latency 响应延迟(毫秒),可选,用于未来优化
|
|
279
|
-
*/
|
|
280
|
-
recordSuccess(peerId: string, taskId: string, delta: number = 10, latency?: number): void {
|
|
281
|
-
// 验证 latency 参数
|
|
282
|
-
if (latency !== undefined) {
|
|
283
|
-
if (typeof latency !== 'number' || !Number.isFinite(latency)) {
|
|
284
|
-
this.logger.warn('Invalid latency value, ignoring', {
|
|
285
|
-
peerId: peerId.slice(0, 16),
|
|
286
|
-
latency
|
|
287
|
-
});
|
|
288
|
-
latency = undefined;
|
|
289
|
-
} else if (latency < 0) {
|
|
290
|
-
this.logger.warn('Negative latency value, treating as 0', {
|
|
291
|
-
peerId: peerId.slice(0, 16),
|
|
292
|
-
latency
|
|
293
|
-
});
|
|
294
|
-
latency = 0;
|
|
295
|
-
} else if (latency > this.config.maxLatency) {
|
|
296
|
-
this.logger.warn('Latency exceeds max, capping', {
|
|
297
|
-
peerId: peerId.slice(0, 16),
|
|
298
|
-
latency,
|
|
299
|
-
maxLatency: this.config.maxLatency
|
|
300
|
-
});
|
|
301
|
-
latency = this.config.maxLatency;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const entry = this.getReputation(peerId);
|
|
306
|
-
const newScore = this.updateScoreEWMA(entry.score, delta);
|
|
307
|
-
|
|
308
|
-
entry.score = newScore;
|
|
309
|
-
entry.level = this.getTier(newScore).level;
|
|
310
|
-
entry.lastUpdated = Date.now();
|
|
311
|
-
entry.history.push({
|
|
312
|
-
type: 'task_success',
|
|
313
|
-
delta,
|
|
314
|
-
timestamp: Date.now(),
|
|
315
|
-
taskId,
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
// 截断历史记录,防止无限增长
|
|
319
|
-
if (entry.history.length > this.config.maxHistory) {
|
|
320
|
-
entry.history = entry.history.slice(-this.config.maxHistory);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
this.logger.info('Reputation updated', {
|
|
324
|
-
peerId: peerId.slice(0, 16),
|
|
325
|
-
delta,
|
|
326
|
-
newScore,
|
|
327
|
-
level: entry.level,
|
|
328
|
-
latency
|
|
329
|
-
});
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* 记录任务失败
|
|
334
|
-
* 会降低节点的信誉分数
|
|
335
|
-
* @param peerId - 节点的唯一标识符
|
|
336
|
-
* @param taskId - 失败任务的 ID
|
|
337
|
-
* @param reason - 可选的失败原因描述
|
|
338
|
-
* @param delta - 分数变化量,默认为 -20
|
|
339
|
-
*/
|
|
340
|
-
recordFailure(peerId: string, taskId: string, reason?: string, delta: number = -20): void {
|
|
341
|
-
const entry = this.getReputation(peerId);
|
|
342
|
-
const newScore = this.updateScoreEWMA(entry.score, delta);
|
|
343
|
-
|
|
344
|
-
entry.score = newScore;
|
|
345
|
-
entry.level = this.getTier(newScore).level;
|
|
346
|
-
entry.lastUpdated = Date.now();
|
|
347
|
-
entry.history.push({
|
|
348
|
-
type: 'task_failure',
|
|
349
|
-
delta,
|
|
350
|
-
timestamp: Date.now(),
|
|
351
|
-
reason,
|
|
352
|
-
taskId,
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
// 截断历史记录
|
|
356
|
-
if (entry.history.length > this.config.maxHistory) {
|
|
357
|
-
entry.history = entry.history.slice(-this.config.maxHistory);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
this.logger.warn('Reputation decreased', {
|
|
361
|
-
peerId: peerId.slice(0, 16),
|
|
362
|
-
delta,
|
|
363
|
-
newScore,
|
|
364
|
-
level: entry.level,
|
|
365
|
-
reason,
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* 记录任务拒绝
|
|
371
|
-
* 当节点拒绝接受任务时调用,会轻微降低信誉分数
|
|
372
|
-
* @param peerId - 节点的唯一标识符
|
|
373
|
-
* @param taskId - 被拒绝任务的 ID
|
|
374
|
-
* @param reason - 可选的拒绝原因描述
|
|
375
|
-
* @param delta - 分数变化量,默认为 -5
|
|
376
|
-
*/
|
|
377
|
-
recordRejection(peerId: string, taskId: string, reason?: string, delta: number = -5): void {
|
|
378
|
-
const entry = this.getReputation(peerId);
|
|
379
|
-
const newScore = this.updateScoreEWMA(entry.score, delta);
|
|
380
|
-
|
|
381
|
-
entry.score = newScore;
|
|
382
|
-
entry.level = this.getTier(newScore).level;
|
|
383
|
-
entry.lastUpdated = Date.now();
|
|
384
|
-
entry.history.push({
|
|
385
|
-
type: 'task_rejected',
|
|
386
|
-
delta,
|
|
387
|
-
timestamp: Date.now(),
|
|
388
|
-
reason,
|
|
389
|
-
taskId,
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
// 截断历史记录
|
|
393
|
-
if (entry.history.length > this.config.maxHistory) {
|
|
394
|
-
entry.history = entry.history.slice(-this.config.maxHistory);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
this.logger.info('Reputation updated (rejection)', {
|
|
398
|
-
peerId: peerId.slice(0, 16),
|
|
399
|
-
delta,
|
|
400
|
-
newScore,
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* 记录评审奖励
|
|
406
|
-
* 当节点完成评审任务时调用,会提高信誉分数
|
|
407
|
-
* @param peerId - 节点的唯一标识符
|
|
408
|
-
* @param delta - 分数变化量,默认为 3
|
|
409
|
-
*/
|
|
410
|
-
recordReviewReward(peerId: string, delta: number = 3): void {
|
|
411
|
-
const entry = this.getReputation(peerId);
|
|
412
|
-
const newScore = this.updateScoreEWMA(entry.score, delta);
|
|
413
|
-
|
|
414
|
-
entry.score = newScore;
|
|
415
|
-
entry.level = this.getTier(newScore).level;
|
|
416
|
-
entry.lastUpdated = Date.now();
|
|
417
|
-
entry.history.push({
|
|
418
|
-
type: 'review_given',
|
|
419
|
-
delta,
|
|
420
|
-
timestamp: Date.now(),
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
// 截断历史记录
|
|
424
|
-
if (entry.history.length > this.config.maxHistory) {
|
|
425
|
-
entry.history = entry.history.slice(-this.config.maxHistory);
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
this.logger.info('Review reward', {
|
|
429
|
-
peerId: peerId.slice(0, 16),
|
|
430
|
-
delta,
|
|
431
|
-
newScore,
|
|
432
|
-
});
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
/**
|
|
436
|
-
* 记录评审惩罚
|
|
437
|
-
* 当节点提供低质量评审或违规时调用,会降低信誉分数
|
|
438
|
-
* @param peerId - 节点的唯一标识符
|
|
439
|
-
* @param delta - 分数变化量,默认为 -5
|
|
440
|
-
* @param reason - 可选的惩罚原因描述
|
|
441
|
-
*/
|
|
442
|
-
recordReviewPenalty(peerId: string, delta: number = -5, reason?: string): void {
|
|
443
|
-
const entry = this.getReputation(peerId);
|
|
444
|
-
const newScore = this.updateScoreEWMA(entry.score, delta);
|
|
445
|
-
|
|
446
|
-
entry.score = newScore;
|
|
447
|
-
entry.level = this.getTier(newScore).level;
|
|
448
|
-
entry.lastUpdated = Date.now();
|
|
449
|
-
entry.history.push({
|
|
450
|
-
type: 'review_penalty',
|
|
451
|
-
delta,
|
|
452
|
-
timestamp: Date.now(),
|
|
453
|
-
reason,
|
|
454
|
-
});
|
|
455
|
-
|
|
456
|
-
// 截断历史记录
|
|
457
|
-
if (entry.history.length > this.config.maxHistory) {
|
|
458
|
-
entry.history = entry.history.slice(-this.config.maxHistory);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
this.logger.warn('Review penalty', {
|
|
462
|
-
peerId: peerId.slice(0, 16),
|
|
463
|
-
delta,
|
|
464
|
-
newScore,
|
|
465
|
-
reason,
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* 获取所有信誉条目
|
|
471
|
-
* 返回按分数从高到低排序的所有节点信誉信息
|
|
472
|
-
* @returns 排序后的信誉条目数组
|
|
473
|
-
*/
|
|
474
|
-
getAllReputations(): ReputationEntry[] {
|
|
475
|
-
return Array.from(this.entries.values()).sort((a, b) => b.score - a.score);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
/**
|
|
479
|
-
* 获取高信誉节点
|
|
480
|
-
* 返回分数达到指定阈值的节点列表,可用于评审任务分配
|
|
481
|
-
* @param minScore - 最低信誉分数阈值,默认为 50
|
|
482
|
-
* @returns 符合条件的信誉条目数组,按分数排序
|
|
483
|
-
*/
|
|
484
|
-
getHighReputationNodes(minScore: number = 50): ReputationEntry[] {
|
|
485
|
-
return this.getAllReputations().filter(e => e.score >= minScore);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* 获取节点的发布优先级
|
|
490
|
-
* 优先级越高,任务分配时越优先被考虑
|
|
491
|
-
* @param peerId - 节点的唯一标识符
|
|
492
|
-
* @returns 发布优先级 (0-5)
|
|
493
|
-
*/
|
|
494
|
-
getPublishPriority(peerId: string): number {
|
|
495
|
-
const entry = this.getReputation(peerId);
|
|
496
|
-
return this.getTier(entry.score).permissions.publishPriority;
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
/**
|
|
500
|
-
* 获取节点的发布折扣
|
|
501
|
-
* 高信誉节点可享受更低的服务费用折扣
|
|
502
|
-
* @param peerId - 节点的唯一标识符
|
|
503
|
-
* @returns 发布折扣率 (0.7-1.0,数值越小折扣越大)
|
|
504
|
-
*/
|
|
505
|
-
getPublishDiscount(peerId: string): number {
|
|
506
|
-
const entry = this.getReputation(peerId);
|
|
507
|
-
return this.getTier(entry.score).permissions.publishDiscount;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* 设置节点的初始信誉分数
|
|
512
|
-
* 用于邀请机制设置被邀请者的初始分数,可覆盖默认初始分数
|
|
513
|
-
* @param peerId - 节点的唯一标识符
|
|
514
|
-
* @param score - 要设置的分数 (0-100),会自动限制在有效范围内
|
|
515
|
-
*/
|
|
516
|
-
setInitialScore(peerId: string, score: number): void {
|
|
517
|
-
const entry = this.getReputation(peerId);
|
|
518
|
-
const clampedScore = Math.max(this.config.minScore, Math.min(this.config.maxScore, score));
|
|
519
|
-
entry.score = clampedScore;
|
|
520
|
-
entry.level = this.getTier(clampedScore).level;
|
|
521
|
-
entry.lastUpdated = Date.now();
|
|
522
|
-
entry.history.push({
|
|
523
|
-
type: 'initial',
|
|
524
|
-
delta: clampedScore - this.config.initialScore,
|
|
525
|
-
timestamp: Date.now(),
|
|
526
|
-
reason: 'Set by invitation system'
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
// 截断历史记录
|
|
530
|
-
if (entry.history.length > this.config.maxHistory) {
|
|
531
|
-
entry.history = entry.history.slice(-this.config.maxHistory);
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
this.logger.info('Initial score set', {
|
|
535
|
-
peerId: peerId.slice(0, 16),
|
|
536
|
-
score: clampedScore,
|
|
537
|
-
level: entry.level
|
|
538
|
-
});
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
// ============================================================================
|
|
542
|
-
// 私有方法
|
|
543
|
-
// ============================================================================
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* 创建初始信誉条目
|
|
547
|
-
*/
|
|
548
|
-
private createInitialEntry(peerId: string): ReputationEntry {
|
|
549
|
-
return {
|
|
550
|
-
peerId,
|
|
551
|
-
score: this.config.initialScore,
|
|
552
|
-
level: this.getTier(this.config.initialScore).level,
|
|
553
|
-
lastUpdated: Date.now(),
|
|
554
|
-
history: [
|
|
555
|
-
{
|
|
556
|
-
type: 'initial',
|
|
557
|
-
delta: 0,
|
|
558
|
-
timestamp: Date.now(),
|
|
559
|
-
},
|
|
560
|
-
],
|
|
561
|
-
};
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* EWMA 分数更新
|
|
566
|
-
* newScore = α * observation + (1 - α) * currentScore
|
|
567
|
-
*/
|
|
568
|
-
private updateScoreEWMA(currentScore: number, delta: number): number {
|
|
569
|
-
const observation = currentScore + delta;
|
|
570
|
-
const newScore = this.config.alpha * observation + (1 - this.config.alpha) * currentScore;
|
|
571
|
-
return Math.max(this.config.minScore, Math.min(this.config.maxScore, newScore));
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// 默认导出
|
|
576
|
-
export default ReputationManager;
|