@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
|
@@ -1,562 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* F2A 信誉安全机制
|
|
3
|
-
* Phase 3: 链式签名、邀请制、挑战机制
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { createHash, createSign, createVerify } from 'crypto';
|
|
7
|
-
import { Logger } from '../utils/logger.js';
|
|
8
|
-
import { ReputationEntry, ReputationManager } from './reputation.js';
|
|
9
|
-
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// 类型定义
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 签名信誉事件
|
|
16
|
-
*/
|
|
17
|
-
export interface SignedReputationEvent {
|
|
18
|
-
peerId: string;
|
|
19
|
-
delta: number;
|
|
20
|
-
prevHash: string;
|
|
21
|
-
timestamp: number;
|
|
22
|
-
signatures: ReviewerSignature[];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 评审者签名
|
|
27
|
-
*/
|
|
28
|
-
export interface ReviewerSignature {
|
|
29
|
-
reviewerId: string;
|
|
30
|
-
signature: string;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 邀请记录
|
|
35
|
-
*/
|
|
36
|
-
export interface InvitationRecord {
|
|
37
|
-
inviterId: string;
|
|
38
|
-
inviteeId: string;
|
|
39
|
-
invitationSignature: string;
|
|
40
|
-
timestamp: number;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 邀请规则配置
|
|
45
|
-
*/
|
|
46
|
-
export interface InvitationConfig {
|
|
47
|
-
minInviterReputation: number;
|
|
48
|
-
maxInvitations: number;
|
|
49
|
-
initialScoreMultiplier: number;
|
|
50
|
-
jointLiability: boolean;
|
|
51
|
-
jointLiabilityRate: number;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* 挑战记录
|
|
56
|
-
*/
|
|
57
|
-
export interface ChallengeRecord {
|
|
58
|
-
challengerId: string;
|
|
59
|
-
targetId: string;
|
|
60
|
-
reason: 'invalid_history' | 'collusion' | 'fake_signatures' | 'score_manipulation';
|
|
61
|
-
evidence: string;
|
|
62
|
-
stake: number;
|
|
63
|
-
timestamp: number;
|
|
64
|
-
status: 'pending' | 'success' | 'failed';
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* 挑战结果
|
|
69
|
-
*/
|
|
70
|
-
export interface ChallengeResult {
|
|
71
|
-
success: boolean;
|
|
72
|
-
reward: number;
|
|
73
|
-
reason: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// ============================================================================
|
|
77
|
-
// 默认配置
|
|
78
|
-
// ============================================================================
|
|
79
|
-
|
|
80
|
-
const DEFAULT_INVITATION_CONFIG: InvitationConfig = {
|
|
81
|
-
minInviterReputation: 60,
|
|
82
|
-
maxInvitations: 5,
|
|
83
|
-
initialScoreMultiplier: 0.5,
|
|
84
|
-
jointLiability: true,
|
|
85
|
-
jointLiabilityRate: 0.3,
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// ============================================================================
|
|
89
|
-
// 链式签名管理器
|
|
90
|
-
// ============================================================================
|
|
91
|
-
|
|
92
|
-
export class ChainSignatureManager {
|
|
93
|
-
private eventChains: Map<string, SignedReputationEvent[]> = new Map();
|
|
94
|
-
private logger: Logger;
|
|
95
|
-
|
|
96
|
-
constructor() {
|
|
97
|
-
this.logger = new Logger({ component: 'ChainSignature' });
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 获取事件链
|
|
102
|
-
*/
|
|
103
|
-
getEventChain(peerId: string): SignedReputationEvent[] {
|
|
104
|
-
return this.eventChains.get(peerId) || [];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* 添加签名事件
|
|
109
|
-
*/
|
|
110
|
-
addSignedEvent(event: SignedReputationEvent): boolean {
|
|
111
|
-
// 验证 prevHash
|
|
112
|
-
const chain = this.getEventChain(event.peerId);
|
|
113
|
-
|
|
114
|
-
if (chain.length === 0) {
|
|
115
|
-
if (event.prevHash !== 'genesis') {
|
|
116
|
-
this.logger.error('Invalid genesis event', { peerId: event.peerId });
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
} else {
|
|
120
|
-
const lastEvent = chain[chain.length - 1];
|
|
121
|
-
const expectedPrevHash = this.hashEvent(lastEvent);
|
|
122
|
-
|
|
123
|
-
if (event.prevHash !== expectedPrevHash) {
|
|
124
|
-
this.logger.error('Chain broken', { peerId: event.peerId });
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
chain.push(event);
|
|
130
|
-
this.eventChains.set(event.peerId, chain);
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* 验证事件链完整性
|
|
136
|
-
*/
|
|
137
|
-
verifyChain(peerId: string): boolean {
|
|
138
|
-
const chain = this.getEventChain(peerId);
|
|
139
|
-
|
|
140
|
-
if (chain.length === 0) return true;
|
|
141
|
-
|
|
142
|
-
let prevHash = 'genesis';
|
|
143
|
-
|
|
144
|
-
for (const event of chain) {
|
|
145
|
-
// 检查 prevHash
|
|
146
|
-
if (event.prevHash !== prevHash) {
|
|
147
|
-
this.logger.error('Chain verification failed', {
|
|
148
|
-
peerId,
|
|
149
|
-
eventIndex: chain.indexOf(event),
|
|
150
|
-
});
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
prevHash = this.hashEvent(event);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* 计算事件哈希
|
|
162
|
-
*/
|
|
163
|
-
hashEvent(event: SignedReputationEvent): string {
|
|
164
|
-
const data = JSON.stringify({
|
|
165
|
-
peerId: event.peerId,
|
|
166
|
-
delta: event.delta,
|
|
167
|
-
prevHash: event.prevHash,
|
|
168
|
-
timestamp: event.timestamp,
|
|
169
|
-
});
|
|
170
|
-
return createHash('sha256').update(data).digest('hex');
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* 创建签名事件
|
|
175
|
-
*/
|
|
176
|
-
createSignedEvent(
|
|
177
|
-
peerId: string,
|
|
178
|
-
delta: number,
|
|
179
|
-
signatures: ReviewerSignature[]
|
|
180
|
-
): SignedReputationEvent {
|
|
181
|
-
const chain = this.getEventChain(peerId);
|
|
182
|
-
const lastEvent = chain.length > 0 ? chain[chain.length - 1] : null;
|
|
183
|
-
|
|
184
|
-
return {
|
|
185
|
-
peerId,
|
|
186
|
-
delta,
|
|
187
|
-
prevHash: lastEvent ? this.hashEvent(lastEvent) : 'genesis',
|
|
188
|
-
timestamp: Date.now(),
|
|
189
|
-
signatures,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* 从事件链计算信誉分
|
|
195
|
-
*/
|
|
196
|
-
calculateScoreFromChain(peerId: string, initialScore: number = 70): number {
|
|
197
|
-
const chain = this.getEventChain(peerId);
|
|
198
|
-
let score = initialScore;
|
|
199
|
-
|
|
200
|
-
for (const event of chain) {
|
|
201
|
-
score = Math.max(0, Math.min(100, score + event.delta));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return score;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* 导出事件链
|
|
209
|
-
*/
|
|
210
|
-
exportChain(peerId: string): string {
|
|
211
|
-
const chain = this.getEventChain(peerId);
|
|
212
|
-
return JSON.stringify(chain);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* 导入事件链
|
|
217
|
-
*/
|
|
218
|
-
importChain(peerId: string, data: string): boolean {
|
|
219
|
-
try {
|
|
220
|
-
const chain = JSON.parse(data) as SignedReputationEvent[];
|
|
221
|
-
this.eventChains.set(peerId, chain);
|
|
222
|
-
return this.verifyChain(peerId);
|
|
223
|
-
} catch {
|
|
224
|
-
return false;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// ============================================================================
|
|
230
|
-
// 邀请管理器
|
|
231
|
-
// ============================================================================
|
|
232
|
-
|
|
233
|
-
export class InvitationManager {
|
|
234
|
-
private config: InvitationConfig;
|
|
235
|
-
private reputationManager: ReputationManager;
|
|
236
|
-
private invitations: Map<string, InvitationRecord[]> = new Map();
|
|
237
|
-
private inviteeToInviter: Map<string, string> = new Map();
|
|
238
|
-
private logger: Logger;
|
|
239
|
-
|
|
240
|
-
constructor(
|
|
241
|
-
reputationManager: ReputationManager,
|
|
242
|
-
config: Partial<InvitationConfig> = {}
|
|
243
|
-
) {
|
|
244
|
-
this.config = { ...DEFAULT_INVITATION_CONFIG, ...config };
|
|
245
|
-
this.reputationManager = reputationManager;
|
|
246
|
-
this.logger = new Logger({ component: 'InvitationManager' });
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* 创建邀请
|
|
251
|
-
*/
|
|
252
|
-
createInvitation(
|
|
253
|
-
inviterId: string,
|
|
254
|
-
inviteeId: string
|
|
255
|
-
): { success: boolean; invitation?: InvitationRecord; error?: string } {
|
|
256
|
-
// 检查邀请者信誉
|
|
257
|
-
const inviterRep = this.reputationManager.getReputation(inviterId);
|
|
258
|
-
|
|
259
|
-
if (inviterRep.score < this.config.minInviterReputation) {
|
|
260
|
-
return {
|
|
261
|
-
success: false,
|
|
262
|
-
error: `Inviter reputation ${inviterRep.score} below minimum ${this.config.minInviterReputation}`,
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// 检查邀请配额
|
|
267
|
-
const invitationCount = this.getInvitationCount(inviterId);
|
|
268
|
-
|
|
269
|
-
if (invitationCount >= this.config.maxInvitations) {
|
|
270
|
-
return {
|
|
271
|
-
success: false,
|
|
272
|
-
error: `Invitation quota exhausted (${invitationCount}/${this.config.maxInvitations})`,
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// 检查是否已被邀请
|
|
277
|
-
if (this.inviteeToInviter.has(inviteeId)) {
|
|
278
|
-
return {
|
|
279
|
-
success: false,
|
|
280
|
-
error: 'Invitee already invited by another node',
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// 创建邀请记录
|
|
285
|
-
const invitation: InvitationRecord = {
|
|
286
|
-
inviterId,
|
|
287
|
-
inviteeId,
|
|
288
|
-
invitationSignature: this.generateSignature(inviterId, inviteeId),
|
|
289
|
-
timestamp: Date.now(),
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
// 记录邀请
|
|
293
|
-
const inviterInvitations = this.invitations.get(inviterId) || [];
|
|
294
|
-
inviterInvitations.push(invitation);
|
|
295
|
-
this.invitations.set(inviterId, inviterInvitations);
|
|
296
|
-
this.inviteeToInviter.set(inviteeId, inviterId);
|
|
297
|
-
|
|
298
|
-
// 设置被邀请者的初始信誉
|
|
299
|
-
const initialScore = Math.max(
|
|
300
|
-
30,
|
|
301
|
-
Math.floor(inviterRep.score * this.config.initialScoreMultiplier)
|
|
302
|
-
);
|
|
303
|
-
// 使用 ReputationManager 的公开方法设置初始分数
|
|
304
|
-
this.reputationManager.setInitialScore(inviteeId, initialScore);
|
|
305
|
-
|
|
306
|
-
this.logger.info('Invitation created', {
|
|
307
|
-
inviterId: inviterId.slice(0, 16),
|
|
308
|
-
inviteeId: inviteeId.slice(0, 16),
|
|
309
|
-
initialScore,
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
return { success: true, invitation };
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* 获取邀请者
|
|
317
|
-
*/
|
|
318
|
-
getInviter(inviteeId: string): string | null {
|
|
319
|
-
return this.inviteeToInviter.get(inviteeId) || null;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* 获取邀请数量
|
|
324
|
-
*/
|
|
325
|
-
getInvitationCount(inviterId: string): number {
|
|
326
|
-
return this.invitations.get(inviterId)?.length || 0;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* 执行连带责任惩罚
|
|
331
|
-
*/
|
|
332
|
-
applyJointLiability(inviteeId: string, penalty: number): void {
|
|
333
|
-
if (!this.config.jointLiability) return;
|
|
334
|
-
|
|
335
|
-
const inviterId = this.getInviter(inviteeId);
|
|
336
|
-
if (!inviterId) return;
|
|
337
|
-
|
|
338
|
-
const jointPenalty = Math.floor(penalty * this.config.jointLiabilityRate);
|
|
339
|
-
|
|
340
|
-
this.reputationManager.recordFailure(
|
|
341
|
-
inviterId,
|
|
342
|
-
`joint-liability-${inviteeId}`,
|
|
343
|
-
`Joint liability for invitee ${inviteeId}`,
|
|
344
|
-
-jointPenalty
|
|
345
|
-
);
|
|
346
|
-
|
|
347
|
-
this.logger.warn('Joint liability applied', {
|
|
348
|
-
inviterId: inviterId.slice(0, 16),
|
|
349
|
-
inviteeId: inviteeId.slice(0, 16),
|
|
350
|
-
jointPenalty,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* 获取所有邀请
|
|
356
|
-
*/
|
|
357
|
-
getAllInvitations(): InvitationRecord[] {
|
|
358
|
-
const all: InvitationRecord[] = [];
|
|
359
|
-
for (const invitations of this.invitations.values()) {
|
|
360
|
-
all.push(...invitations);
|
|
361
|
-
}
|
|
362
|
-
return all;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* 生成签名
|
|
367
|
-
*/
|
|
368
|
-
private generateSignature(inviterId: string, inviteeId: string): string {
|
|
369
|
-
const data = `${inviterId}:${inviteeId}:${Date.now()}`;
|
|
370
|
-
return createHash('sha256').update(data).digest('hex');
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// ============================================================================
|
|
375
|
-
// 挑战管理器
|
|
376
|
-
// ============================================================================
|
|
377
|
-
|
|
378
|
-
export class ChallengeManager {
|
|
379
|
-
private reputationManager: ReputationManager;
|
|
380
|
-
private chainManager: ChainSignatureManager;
|
|
381
|
-
private challenges: Map<string, ChallengeRecord[]> = new Map();
|
|
382
|
-
private logger: Logger;
|
|
383
|
-
|
|
384
|
-
constructor(
|
|
385
|
-
reputationManager: ReputationManager,
|
|
386
|
-
chainManager: ChainSignatureManager
|
|
387
|
-
) {
|
|
388
|
-
this.reputationManager = reputationManager;
|
|
389
|
-
this.chainManager = chainManager;
|
|
390
|
-
this.logger = new Logger({ component: 'ChallengeManager' });
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/**
|
|
394
|
-
* 提交挑战
|
|
395
|
-
*/
|
|
396
|
-
submitChallenge(
|
|
397
|
-
challengerId: string,
|
|
398
|
-
targetId: string,
|
|
399
|
-
reason: ChallengeRecord['reason'],
|
|
400
|
-
evidence: string,
|
|
401
|
-
stake: number = 10
|
|
402
|
-
): ChallengeRecord {
|
|
403
|
-
const challenge: ChallengeRecord = {
|
|
404
|
-
challengerId,
|
|
405
|
-
targetId,
|
|
406
|
-
reason,
|
|
407
|
-
evidence,
|
|
408
|
-
stake,
|
|
409
|
-
timestamp: Date.now(),
|
|
410
|
-
status: 'pending',
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
const targetChallenges = this.challenges.get(targetId) || [];
|
|
414
|
-
targetChallenges.push(challenge);
|
|
415
|
-
this.challenges.set(targetId, targetChallenges);
|
|
416
|
-
|
|
417
|
-
this.logger.info('Challenge submitted', {
|
|
418
|
-
challengerId: challengerId.slice(0, 16),
|
|
419
|
-
targetId: targetId.slice(0, 16),
|
|
420
|
-
reason,
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
return challenge;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* 处理挑战
|
|
428
|
-
*/
|
|
429
|
-
processChallenge(challenge: ChallengeRecord): ChallengeResult {
|
|
430
|
-
const targetId = challenge.targetId;
|
|
431
|
-
|
|
432
|
-
// 1. 验证事件链
|
|
433
|
-
if (challenge.reason === 'invalid_history' || challenge.reason === 'fake_signatures') {
|
|
434
|
-
const chainValid = this.chainManager.verifyChain(targetId);
|
|
435
|
-
|
|
436
|
-
if (!chainValid) {
|
|
437
|
-
// 挑战成功
|
|
438
|
-
this.reputationManager.recordFailure(
|
|
439
|
-
targetId,
|
|
440
|
-
'challenge-invalid-chain',
|
|
441
|
-
'Invalid reputation chain detected',
|
|
442
|
-
-50
|
|
443
|
-
);
|
|
444
|
-
|
|
445
|
-
// 奖励挑战者
|
|
446
|
-
this.reputationManager.recordReviewReward(
|
|
447
|
-
challenge.challengerId,
|
|
448
|
-
challenge.stake * 2
|
|
449
|
-
);
|
|
450
|
-
|
|
451
|
-
challenge.status = 'success';
|
|
452
|
-
return { success: true, reward: challenge.stake * 2, reason: 'Invalid chain detected' };
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// 2. 检测合谋
|
|
457
|
-
if (challenge.reason === 'collusion') {
|
|
458
|
-
const collusionScore = this.detectCollusion(targetId);
|
|
459
|
-
|
|
460
|
-
if (collusionScore > 0.8) {
|
|
461
|
-
// 合谋检测成功
|
|
462
|
-
this.reputationManager.recordFailure(
|
|
463
|
-
targetId,
|
|
464
|
-
'challenge-collusion',
|
|
465
|
-
'Collusion detected',
|
|
466
|
-
-30
|
|
467
|
-
);
|
|
468
|
-
|
|
469
|
-
this.reputationManager.recordReviewReward(
|
|
470
|
-
challenge.challengerId,
|
|
471
|
-
challenge.stake * 1.5
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
challenge.status = 'success';
|
|
475
|
-
return { success: true, reward: challenge.stake * 1.5, reason: 'Collusion detected' };
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// 3. 分数操纵检测
|
|
480
|
-
if (challenge.reason === 'score_manipulation') {
|
|
481
|
-
const chain = this.chainManager.getEventChain(targetId);
|
|
482
|
-
const calculatedScore = this.chainManager.calculateScoreFromChain(targetId);
|
|
483
|
-
const claimedScore = this.reputationManager.getReputation(targetId).score;
|
|
484
|
-
|
|
485
|
-
if (Math.abs(calculatedScore - claimedScore) > 10) {
|
|
486
|
-
// 分数不一致
|
|
487
|
-
this.reputationManager.recordFailure(
|
|
488
|
-
targetId,
|
|
489
|
-
'challenge-score-manipulation',
|
|
490
|
-
'Score manipulation detected',
|
|
491
|
-
-20
|
|
492
|
-
);
|
|
493
|
-
|
|
494
|
-
this.reputationManager.recordReviewReward(
|
|
495
|
-
challenge.challengerId,
|
|
496
|
-
challenge.stake * 1.5
|
|
497
|
-
);
|
|
498
|
-
|
|
499
|
-
challenge.status = 'success';
|
|
500
|
-
return { success: true, reward: challenge.stake * 1.5, reason: 'Score manipulation detected' };
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// 挑战失败
|
|
505
|
-
this.reputationManager.recordReviewPenalty(
|
|
506
|
-
challenge.challengerId,
|
|
507
|
-
-challenge.stake * 0.5,
|
|
508
|
-
'Failed challenge'
|
|
509
|
-
);
|
|
510
|
-
|
|
511
|
-
challenge.status = 'failed';
|
|
512
|
-
return { success: false, reward: 0, reason: 'Challenge failed' };
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* 合谋检测算法
|
|
517
|
-
*/
|
|
518
|
-
detectCollusion(nodeId: string): number {
|
|
519
|
-
const entry = this.reputationManager.getReputation(nodeId);
|
|
520
|
-
|
|
521
|
-
// 分析评审历史
|
|
522
|
-
const successEvents = entry.history.filter(e => e.type === 'task_success');
|
|
523
|
-
|
|
524
|
-
if (successEvents.length < 5) return 0;
|
|
525
|
-
|
|
526
|
-
// 简单检测:如果所有成功事件都是同一任务类型,可疑度低
|
|
527
|
-
// 如果成功事件分数波动极大,可疑度高
|
|
528
|
-
const deltas = successEvents.map(e => e.delta);
|
|
529
|
-
const avgDelta = deltas.reduce((a, b) => a + b, 0) / deltas.length;
|
|
530
|
-
const variance = deltas.reduce((sum, d) => sum + Math.pow(d - avgDelta, 2), 0) / deltas.length;
|
|
531
|
-
|
|
532
|
-
// 方差越大,可疑度越高
|
|
533
|
-
const normalizedVariance = Math.min(1, variance / 100);
|
|
534
|
-
|
|
535
|
-
return normalizedVariance;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
/**
|
|
539
|
-
* 获取挑战历史
|
|
540
|
-
*/
|
|
541
|
-
getChallenges(targetId: string): ChallengeRecord[] {
|
|
542
|
-
return this.challenges.get(targetId) || [];
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
/**
|
|
546
|
-
* 获取待处理挑战
|
|
547
|
-
*/
|
|
548
|
-
getPendingChallenges(): ChallengeRecord[] {
|
|
549
|
-
const all: ChallengeRecord[] = [];
|
|
550
|
-
for (const challenges of this.challenges.values()) {
|
|
551
|
-
all.push(...challenges.filter(c => c.status === 'pending'));
|
|
552
|
-
}
|
|
553
|
-
return all;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
// 默认导出
|
|
558
|
-
export default {
|
|
559
|
-
ChainSignatureManager,
|
|
560
|
-
InvitationManager,
|
|
561
|
-
ChallengeManager,
|
|
562
|
-
};
|