@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,428 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* F2A 自治经济系统
|
|
3
|
-
* Phase 4: 信誉消耗、评审激励、优先级调度
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Logger } from '../utils/logger.js';
|
|
7
|
-
import { ReputationManager } from './reputation.js';
|
|
8
|
-
import { ReviewCommittee, ReviewResult } from './review-committee.js';
|
|
9
|
-
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// 类型定义
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 任务请求
|
|
16
|
-
*/
|
|
17
|
-
export interface TaskRequest {
|
|
18
|
-
taskId: string;
|
|
19
|
-
requesterId: string;
|
|
20
|
-
capability: string;
|
|
21
|
-
description: string;
|
|
22
|
-
parameters?: Record<string, unknown>;
|
|
23
|
-
timeout?: number;
|
|
24
|
-
estimatedComplexity?: number;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* 任务成本估算
|
|
29
|
-
*/
|
|
30
|
-
export interface TaskCost {
|
|
31
|
-
baseCost: number;
|
|
32
|
-
discount: number;
|
|
33
|
-
finalCost: number;
|
|
34
|
-
priority: number;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 任务奖励
|
|
39
|
-
*/
|
|
40
|
-
export interface TaskReward {
|
|
41
|
-
executorReward: number;
|
|
42
|
-
reviewerReward: number;
|
|
43
|
-
requesterRefund: number;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 经济配置
|
|
48
|
-
*/
|
|
49
|
-
export interface EconomyConfig {
|
|
50
|
-
/** 基础任务成本 */
|
|
51
|
-
baseTaskCost: number;
|
|
52
|
-
/** 复杂度系数 */
|
|
53
|
-
complexityMultiplier: number;
|
|
54
|
-
/** 执行者奖励比例 */
|
|
55
|
-
executorRewardRate: number;
|
|
56
|
-
/** 评审者奖励比例 */
|
|
57
|
-
reviewerRewardRate: number;
|
|
58
|
-
/** 任务超时惩罚 */
|
|
59
|
-
timeoutPenalty: number;
|
|
60
|
-
/** 拒绝任务惩罚 */
|
|
61
|
-
rejectionPenalty: number;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* 优先级队列项
|
|
66
|
-
*/
|
|
67
|
-
export interface PriorityQueueItem {
|
|
68
|
-
task: TaskRequest;
|
|
69
|
-
priority: number;
|
|
70
|
-
cost: number;
|
|
71
|
-
deducted: boolean;
|
|
72
|
-
timestamp: number;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* 任务执行结果
|
|
77
|
-
*/
|
|
78
|
-
export interface TaskExecutionResult {
|
|
79
|
-
taskId: string;
|
|
80
|
-
executorId: string;
|
|
81
|
-
status: 'success' | 'failure' | 'timeout' | 'rejected';
|
|
82
|
-
result?: unknown;
|
|
83
|
-
error?: string;
|
|
84
|
-
reviewResult?: ReviewResult;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ============================================================================
|
|
88
|
-
// 默认配置
|
|
89
|
-
// ============================================================================
|
|
90
|
-
|
|
91
|
-
const DEFAULT_ECONOMY_CONFIG: EconomyConfig = {
|
|
92
|
-
baseTaskCost: 5,
|
|
93
|
-
complexityMultiplier: 0.1,
|
|
94
|
-
executorRewardRate: 0.5,
|
|
95
|
-
reviewerRewardRate: 0.2,
|
|
96
|
-
timeoutPenalty: 15,
|
|
97
|
-
rejectionPenalty: 5,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// ============================================================================
|
|
101
|
-
// 自治经济管理器
|
|
102
|
-
// ============================================================================
|
|
103
|
-
|
|
104
|
-
export class AutonomousEconomy {
|
|
105
|
-
private config: EconomyConfig;
|
|
106
|
-
private reputationManager: ReputationManager;
|
|
107
|
-
private reviewCommittee: ReviewCommittee;
|
|
108
|
-
private taskQueue: PriorityQueueItem[] = [];
|
|
109
|
-
private pendingTasks: Map<string, PriorityQueueItem> = new Map();
|
|
110
|
-
private logger: Logger;
|
|
111
|
-
|
|
112
|
-
constructor(
|
|
113
|
-
reputationManager: ReputationManager,
|
|
114
|
-
reviewCommittee: ReviewCommittee,
|
|
115
|
-
config: Partial<EconomyConfig> = {}
|
|
116
|
-
) {
|
|
117
|
-
this.config = { ...DEFAULT_ECONOMY_CONFIG, ...config };
|
|
118
|
-
this.reputationManager = reputationManager;
|
|
119
|
-
this.reviewCommittee = reviewCommittee;
|
|
120
|
-
this.logger = new Logger({ component: 'AutonomousEconomy' });
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* 提交任务(消耗信誉)
|
|
125
|
-
*/
|
|
126
|
-
submitTask(task: TaskRequest): { success: boolean; cost?: TaskCost; error?: string } {
|
|
127
|
-
// 检查发布权限
|
|
128
|
-
if (!this.reputationManager.hasPermission(task.requesterId, 'publish')) {
|
|
129
|
-
return { success: false, error: 'No permission to publish tasks' };
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// 计算成本
|
|
133
|
-
const cost = this.calculateTaskCost(task);
|
|
134
|
-
|
|
135
|
-
// 检查信誉是否足够
|
|
136
|
-
const reputation = this.reputationManager.getReputation(task.requesterId);
|
|
137
|
-
if (reputation.score < cost.finalCost) {
|
|
138
|
-
return {
|
|
139
|
-
success: false,
|
|
140
|
-
error: `Insufficient reputation: ${reputation.score.toFixed(1)} < ${cost.finalCost.toFixed(1)}`,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// 预扣信誉
|
|
145
|
-
this.reputationManager.recordFailure(
|
|
146
|
-
task.requesterId,
|
|
147
|
-
`task-submit-${task.taskId}`,
|
|
148
|
-
'Task submission cost',
|
|
149
|
-
-cost.finalCost
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
// 加入优先级队列
|
|
153
|
-
const queueItem: PriorityQueueItem = {
|
|
154
|
-
task,
|
|
155
|
-
priority: cost.priority,
|
|
156
|
-
cost: cost.finalCost,
|
|
157
|
-
deducted: true,
|
|
158
|
-
timestamp: Date.now(),
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
this.taskQueue.push(queueItem);
|
|
162
|
-
this.taskQueue.sort((a, b) => b.priority - a.priority);
|
|
163
|
-
this.pendingTasks.set(task.taskId, queueItem);
|
|
164
|
-
|
|
165
|
-
this.logger.info('Task submitted', {
|
|
166
|
-
taskId: task.taskId,
|
|
167
|
-
requesterId: task.requesterId.slice(0, 16),
|
|
168
|
-
cost: cost.finalCost,
|
|
169
|
-
priority: cost.priority,
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
return { success: true, cost };
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* 计算任务成本
|
|
177
|
-
*/
|
|
178
|
-
calculateTaskCost(task: TaskRequest): TaskCost {
|
|
179
|
-
const complexity = task.estimatedComplexity || 1;
|
|
180
|
-
const baseCost = this.config.baseTaskCost * complexity;
|
|
181
|
-
|
|
182
|
-
// 获取折扣
|
|
183
|
-
const discount = this.reputationManager.getPublishDiscount(task.requesterId);
|
|
184
|
-
const finalCost = Math.floor(baseCost * discount);
|
|
185
|
-
|
|
186
|
-
// 获取优先级
|
|
187
|
-
const priority = this.reputationManager.getPublishPriority(task.requesterId);
|
|
188
|
-
|
|
189
|
-
return {
|
|
190
|
-
baseCost,
|
|
191
|
-
discount,
|
|
192
|
-
finalCost,
|
|
193
|
-
priority,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* 分配任务给执行者
|
|
199
|
-
*/
|
|
200
|
-
assignTask(taskId: string, executorId: string): boolean {
|
|
201
|
-
const queueItem = this.pendingTasks.get(taskId);
|
|
202
|
-
if (!queueItem) return false;
|
|
203
|
-
|
|
204
|
-
// 检查执行者权限
|
|
205
|
-
if (!this.reputationManager.hasPermission(executorId, 'execute')) {
|
|
206
|
-
this.logger.warn('Executor lacks permission', { executorId: executorId.slice(0, 16) });
|
|
207
|
-
return false;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
this.logger.info('Task assigned', {
|
|
211
|
-
taskId,
|
|
212
|
-
executorId: executorId.slice(0, 16),
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* 完成任务并结算
|
|
220
|
-
*/
|
|
221
|
-
completeTask(result: TaskExecutionResult): TaskReward | null {
|
|
222
|
-
const queueItem = this.pendingTasks.get(result.taskId);
|
|
223
|
-
if (!queueItem) return null;
|
|
224
|
-
|
|
225
|
-
const task = queueItem.task;
|
|
226
|
-
let reward: TaskReward = {
|
|
227
|
-
executorReward: 0,
|
|
228
|
-
reviewerReward: 0,
|
|
229
|
-
requesterRefund: 0,
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
switch (result.status) {
|
|
233
|
-
case 'success':
|
|
234
|
-
// 任务成功
|
|
235
|
-
if (result.reviewResult) {
|
|
236
|
-
reward = this.calculateRewardFromReview(
|
|
237
|
-
task,
|
|
238
|
-
result.executorId,
|
|
239
|
-
result.reviewResult
|
|
240
|
-
);
|
|
241
|
-
} else {
|
|
242
|
-
// 无评审结果,使用默认奖励
|
|
243
|
-
reward.executorReward = queueItem.cost * this.config.executorRewardRate;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// 奖励执行者
|
|
247
|
-
this.reputationManager.recordSuccess(
|
|
248
|
-
result.executorId,
|
|
249
|
-
result.taskId,
|
|
250
|
-
reward.executorReward
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
// 部分返还请求者
|
|
254
|
-
if (reward.requesterRefund > 0) {
|
|
255
|
-
this.reputationManager.recordSuccess(
|
|
256
|
-
task.requesterId,
|
|
257
|
-
`refund-${result.taskId}`,
|
|
258
|
-
reward.requesterRefund
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
this.logger.info('Task completed successfully', {
|
|
263
|
-
taskId: result.taskId,
|
|
264
|
-
executorReward: reward.executorReward,
|
|
265
|
-
requesterRefund: reward.requesterRefund,
|
|
266
|
-
});
|
|
267
|
-
break;
|
|
268
|
-
|
|
269
|
-
case 'failure':
|
|
270
|
-
// 任务失败
|
|
271
|
-
this.reputationManager.recordFailure(
|
|
272
|
-
result.executorId,
|
|
273
|
-
result.taskId,
|
|
274
|
-
result.error || 'Task failed'
|
|
275
|
-
);
|
|
276
|
-
this.logger.warn('Task failed', { taskId: result.taskId, error: result.error });
|
|
277
|
-
break;
|
|
278
|
-
|
|
279
|
-
case 'timeout':
|
|
280
|
-
// 任务超时
|
|
281
|
-
this.reputationManager.recordFailure(
|
|
282
|
-
result.executorId,
|
|
283
|
-
result.taskId,
|
|
284
|
-
'Task timeout',
|
|
285
|
-
-this.config.timeoutPenalty
|
|
286
|
-
);
|
|
287
|
-
this.logger.warn('Task timeout', { taskId: result.taskId });
|
|
288
|
-
break;
|
|
289
|
-
|
|
290
|
-
case 'rejected':
|
|
291
|
-
// 任务被拒绝
|
|
292
|
-
this.reputationManager.recordRejection(
|
|
293
|
-
result.executorId,
|
|
294
|
-
result.taskId,
|
|
295
|
-
result.error || 'Task rejected'
|
|
296
|
-
);
|
|
297
|
-
break;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// 清理
|
|
301
|
-
this.pendingTasks.delete(result.taskId);
|
|
302
|
-
this.taskQueue = this.taskQueue.filter(item => item.task.taskId !== result.taskId);
|
|
303
|
-
|
|
304
|
-
return reward;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* 从评审结果计算奖励
|
|
309
|
-
*/
|
|
310
|
-
calculateRewardFromReview(
|
|
311
|
-
task: TaskRequest,
|
|
312
|
-
executorId: string,
|
|
313
|
-
reviewResult: ReviewResult
|
|
314
|
-
): TaskReward {
|
|
315
|
-
const { finalWorkload, finalValue } = reviewResult;
|
|
316
|
-
|
|
317
|
-
// 执行者奖励 = 工作量 × 价值系数
|
|
318
|
-
const valueFactor = (finalValue + 100) / 200; // 归一化到 0-1
|
|
319
|
-
const executorReward = finalWorkload * valueFactor * this.config.executorRewardRate;
|
|
320
|
-
|
|
321
|
-
// 评审者奖励(在 ReviewCommittee 中已处理)
|
|
322
|
-
const reviewerReward = reviewResult.reviews.length * 3;
|
|
323
|
-
|
|
324
|
-
// 请求者返还
|
|
325
|
-
let requesterRefund = 0;
|
|
326
|
-
if (finalValue > 0) {
|
|
327
|
-
// 正价值任务,部分返还
|
|
328
|
-
requesterRefund = finalWorkload * 0.1;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
return {
|
|
332
|
-
executorReward,
|
|
333
|
-
reviewerReward,
|
|
334
|
-
requesterRefund,
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* 获取下一个待处理任务
|
|
340
|
-
*/
|
|
341
|
-
getNextTask(): PriorityQueueItem | null {
|
|
342
|
-
return this.taskQueue.length > 0 ? this.taskQueue[0] : null;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* 获取队列长度
|
|
347
|
-
*/
|
|
348
|
-
getQueueLength(): number {
|
|
349
|
-
return this.taskQueue.length;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* 获取待处理任务
|
|
354
|
-
*/
|
|
355
|
-
getPendingTask(taskId: string): PriorityQueueItem | null {
|
|
356
|
-
return this.pendingTasks.get(taskId) || null;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/**
|
|
360
|
-
* 取消任务(返还部分信誉)
|
|
361
|
-
*/
|
|
362
|
-
cancelTask(taskId: string): boolean {
|
|
363
|
-
const queueItem = this.pendingTasks.get(taskId);
|
|
364
|
-
if (!queueItem) return false;
|
|
365
|
-
|
|
366
|
-
// 返还部分信誉
|
|
367
|
-
const refund = queueItem.cost * 0.5;
|
|
368
|
-
this.reputationManager.recordSuccess(
|
|
369
|
-
queueItem.task.requesterId,
|
|
370
|
-
`cancel-${taskId}`,
|
|
371
|
-
refund
|
|
372
|
-
);
|
|
373
|
-
|
|
374
|
-
// 清理
|
|
375
|
-
this.pendingTasks.delete(taskId);
|
|
376
|
-
this.taskQueue = this.taskQueue.filter(item => item.task.taskId !== taskId);
|
|
377
|
-
|
|
378
|
-
this.logger.info('Task cancelled', {
|
|
379
|
-
taskId,
|
|
380
|
-
refund,
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
return true;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* 获取经济统计
|
|
388
|
-
*/
|
|
389
|
-
getEconomyStats(): {
|
|
390
|
-
pendingTasks: number;
|
|
391
|
-
queueLength: number;
|
|
392
|
-
totalCostDeducted: number;
|
|
393
|
-
} {
|
|
394
|
-
const totalCostDeducted = Array.from(this.pendingTasks.values())
|
|
395
|
-
.filter(item => item.deducted)
|
|
396
|
-
.reduce((sum, item) => sum + item.cost, 0);
|
|
397
|
-
|
|
398
|
-
return {
|
|
399
|
-
pendingTasks: this.pendingTasks.size,
|
|
400
|
-
queueLength: this.taskQueue.length,
|
|
401
|
-
totalCostDeducted,
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* 清理过期任务
|
|
407
|
-
*/
|
|
408
|
-
cleanupExpiredTasks(maxAge: number = 24 * 60 * 60 * 1000): string[] {
|
|
409
|
-
const now = Date.now();
|
|
410
|
-
const expired: string[] = [];
|
|
411
|
-
|
|
412
|
-
for (const [taskId, item] of this.pendingTasks) {
|
|
413
|
-
if (now - item.timestamp > maxAge) {
|
|
414
|
-
expired.push(taskId);
|
|
415
|
-
this.cancelTask(taskId);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
if (expired.length > 0) {
|
|
420
|
-
this.logger.info('Cleaned up expired tasks', { count: expired.length });
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
return expired;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
// 默认导出
|
|
428
|
-
export default AutonomousEconomy;
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { E2EECrypto } from './e2ee-crypto.js';
|
|
3
|
-
|
|
4
|
-
describe('E2EECrypto', () => {
|
|
5
|
-
let cryptoA: E2EECrypto;
|
|
6
|
-
let cryptoB: E2EECrypto;
|
|
7
|
-
|
|
8
|
-
beforeEach(async () => {
|
|
9
|
-
cryptoA = new E2EECrypto();
|
|
10
|
-
cryptoB = new E2EECrypto();
|
|
11
|
-
await cryptoA.initialize();
|
|
12
|
-
await cryptoB.initialize();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
describe('initialization', () => {
|
|
16
|
-
it('should generate key pair on initialize', async () => {
|
|
17
|
-
const publicKey = cryptoA.getPublicKey();
|
|
18
|
-
expect(publicKey).not.toBeNull();
|
|
19
|
-
expect(typeof publicKey).toBe('string');
|
|
20
|
-
expect(publicKey!.length).toBeGreaterThan(0);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('should generate different keys for different instances', async () => {
|
|
24
|
-
const keyA = cryptoA.getPublicKey();
|
|
25
|
-
const keyB = cryptoB.getPublicKey();
|
|
26
|
-
expect(keyA).not.toBe(keyB);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should export and import key pair', () => {
|
|
30
|
-
const exported = cryptoA.exportKeyPair();
|
|
31
|
-
expect(exported).not.toBeNull();
|
|
32
|
-
expect(exported!.publicKey).toBeDefined();
|
|
33
|
-
expect(exported!.privateKey).toBeDefined();
|
|
34
|
-
|
|
35
|
-
// Create new instance and import
|
|
36
|
-
const cryptoC = new E2EECrypto();
|
|
37
|
-
const privateKey = Buffer.from(exported!.privateKey, 'base64');
|
|
38
|
-
const publicKey = Buffer.from(exported!.publicKey, 'base64');
|
|
39
|
-
cryptoC.initializeWithKeyPair(privateKey, publicKey);
|
|
40
|
-
|
|
41
|
-
expect(cryptoC.getPublicKey()).toBe(exported!.publicKey);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe('peer key registration', () => {
|
|
46
|
-
it('should register peer public key', () => {
|
|
47
|
-
const keyB = cryptoB.getPublicKey()!;
|
|
48
|
-
cryptoA.registerPeerPublicKey('peer-b', keyB);
|
|
49
|
-
expect(cryptoA.canEncryptTo('peer-b')).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should track registered peer count', () => {
|
|
53
|
-
expect(cryptoA.getRegisteredPeerCount()).toBe(0);
|
|
54
|
-
cryptoA.registerPeerPublicKey('peer-1', cryptoB.getPublicKey()!);
|
|
55
|
-
expect(cryptoA.getRegisteredPeerCount()).toBe(1);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
describe('encryption/decryption', () => {
|
|
60
|
-
beforeEach(() => {
|
|
61
|
-
// Exchange public keys
|
|
62
|
-
cryptoA.registerPeerPublicKey('peer-b', cryptoB.getPublicKey()!);
|
|
63
|
-
cryptoB.registerPeerPublicKey('peer-a', cryptoA.getPublicKey()!);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('should encrypt and decrypt message', () => {
|
|
67
|
-
const plaintext = 'Hello, secure world!';
|
|
68
|
-
const encrypted = cryptoA.encrypt('peer-b', plaintext);
|
|
69
|
-
|
|
70
|
-
expect(encrypted).not.toBeNull();
|
|
71
|
-
expect(encrypted!.ciphertext).toBeDefined();
|
|
72
|
-
expect(encrypted!.iv).toBeDefined();
|
|
73
|
-
expect(encrypted!.authTag).toBeDefined();
|
|
74
|
-
|
|
75
|
-
const decrypted = cryptoB.decrypt(encrypted!);
|
|
76
|
-
expect(decrypted).toBe(plaintext);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should encrypt with AAD', () => {
|
|
80
|
-
const plaintext = 'Secret message';
|
|
81
|
-
const aad = 'message-metadata';
|
|
82
|
-
|
|
83
|
-
const encrypted = cryptoA.encrypt('peer-b', plaintext, aad);
|
|
84
|
-
expect(encrypted).not.toBeNull();
|
|
85
|
-
expect(encrypted!.aad).toBe(aad);
|
|
86
|
-
|
|
87
|
-
const decrypted = cryptoB.decrypt(encrypted!);
|
|
88
|
-
expect(decrypted).toBe(plaintext);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should fail to decrypt tampered ciphertext', () => {
|
|
92
|
-
const plaintext = 'Original message';
|
|
93
|
-
const encrypted = cryptoA.encrypt('peer-b', plaintext);
|
|
94
|
-
|
|
95
|
-
// Tamper with ciphertext
|
|
96
|
-
encrypted!.ciphertext = encrypted!.ciphertext.slice(0, -4) + 'xxxx';
|
|
97
|
-
|
|
98
|
-
const decrypted = cryptoB.decrypt(encrypted!);
|
|
99
|
-
expect(decrypted).toBeNull(); // Should fail
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('should return null when encrypting to unknown peer', async () => {
|
|
103
|
-
const cryptoC = new E2EECrypto();
|
|
104
|
-
await cryptoC.initialize();
|
|
105
|
-
// Don't register any peer keys
|
|
106
|
-
|
|
107
|
-
const result = cryptoC.encrypt('unknown-peer', 'test');
|
|
108
|
-
expect(result).toBeNull();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
describe('error handling', () => {
|
|
113
|
-
it('should return null when decrypting malformed message', () => {
|
|
114
|
-
const malformed = {
|
|
115
|
-
senderPublicKey: 'invalid-base64!!!',
|
|
116
|
-
iv: Buffer.from('invalid').toString('base64'),
|
|
117
|
-
authTag: Buffer.from('short').toString('base64'),
|
|
118
|
-
ciphertext: 'garbage'
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const decrypted = cryptoA.decrypt(malformed as any);
|
|
122
|
-
expect(decrypted).toBeNull();
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|