@anonympins/fingerprint 0.4.2 → 0.4.4
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/CHANGELOG.md +38 -0
- package/README.md +70 -60
- package/package.json +1 -1
- package/src/js/fingerprint.client.js +831 -635
- package/src/js/fingerprint.js +249 -31
- package/src/js/pow.solver.js +531 -497
- package/src/js/problem-manager.js +24 -0
- package/src/js/tests/fingerprint.client.init.test.js +140 -119
- package/src/js/tests/fingerprint.test.js +2451 -2319
- package/src/js/tests/pow.solver.test.js +233 -197
- package/src/js/tests/problem-manager.test.js +358 -322
- package/src/php/Challenge/ChallengeUtils.php +415 -361
- package/src/php/Config/SecurityProfiles.php +276 -271
- package/src/php/FingerprintClient.php +131 -131
- package/src/php/FingerprintEngine.php +36 -2
- package/src/php/Optimization/FunctionRegistry.php +63 -62
- package/src/php/Optimization/OptimizationOperators.php +401 -304
- package/src/php/ProblemManager.php +29 -0
- package/src/php/RequestContext.php +90 -90
- package/src/php/Store/IStore.php +41 -41
- package/src/php/Store/RedisStore.php +53 -53
- package/src/php/Tests/FingerprintEngineTest.php +330 -299
- package/src/php/Tests/ProblemManagerTest.php +376 -296
- package/src/php/Tests/RequestUtilsTest.php +386 -253
- package/src/php/Tests/problems.config.json +3 -3
- package/src/php/Utils/RequestUtils.php +201 -17
|
@@ -1,198 +1,234 @@
|
|
|
1
|
-
import {describe, expect, it, vi, beforeEach, afterEach} from 'vitest';
|
|
2
|
-
import {createHash} from 'node:crypto';
|
|
3
|
-
// Import the functions to be tested.
|
|
4
|
-
// Since the inline file doesn't use exports, we can't directly import.
|
|
5
|
-
// Instead, we'll test the ES module version which shares the same logic.
|
|
6
|
-
import {solveChallenge, solveCpuTargetInline, solveMemory, solveTsp} from '../pow.solver.js';
|
|
7
|
-
|
|
8
|
-
describe('Proof-of-Work Solvers', () => {
|
|
9
|
-
|
|
10
|
-
describe('solveCpuTargetInline', () => {
|
|
11
|
-
const nonce = 'test-nonce';
|
|
12
|
-
// A relatively easy target for quick tests (first 16 bits must be zero)
|
|
13
|
-
const targetHex = '0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
|
|
14
|
-
const targetBigInt = BigInt('0x' + targetHex);
|
|
15
|
-
|
|
16
|
-
it('should find a valid CPU solution with a simple base block', async () => {
|
|
17
|
-
// Le `baseBlock` est maintenant un Uint8Array.
|
|
18
|
-
// Le client et le serveur doivent s'accorder sur sa construction.
|
|
19
|
-
// Ici, on simule un challenge simple avec juste le nonce.
|
|
20
|
-
const baseBlock = new TextEncoder().encode(`${nonce}:`);
|
|
21
|
-
const solution = await solveCpuTargetInline(baseBlock, targetHex);
|
|
22
|
-
|
|
23
|
-
// Verification: re-hash the solution and check against the target
|
|
24
|
-
const finalBlock = new Uint8Array([...baseBlock, ...new TextEncoder().encode(String(solution))]);
|
|
25
|
-
const hash = createHash('sha256').update(finalBlock).digest('hex');
|
|
26
|
-
const hashBigInt = BigInt('0x' + hash);
|
|
27
|
-
|
|
28
|
-
expect(hashBigInt).toBeLessThan(targetBigInt);
|
|
29
|
-
}, 20000);
|
|
30
|
-
|
|
31
|
-
it('should find a valid CPU solution with a client secret', async () => {
|
|
32
|
-
const clientSecret = 'my-secret';
|
|
33
|
-
const fingerprint = 'test-fp-string';
|
|
34
|
-
// Le `baseBlock` est maintenant un Uint8Array qui inclut toutes les informations.
|
|
35
|
-
const baseBlock = new TextEncoder().encode(`${nonce}:${clientSecret}:${fingerprint}:`);
|
|
36
|
-
const solution = await solveCpuTargetInline(baseBlock, targetHex);
|
|
37
|
-
|
|
38
|
-
// Verification: re-hash the solution and check against the target
|
|
39
|
-
const finalBlock = new Uint8Array([...baseBlock, ...new TextEncoder().encode(String(solution))]);
|
|
40
|
-
const hash = createHash('sha256').update(finalBlock).digest('hex');
|
|
41
|
-
const hashBigInt = BigInt('0x' + hash);
|
|
42
|
-
expect(hashBigInt).toBeLessThan(targetBigInt);
|
|
43
|
-
}, 20000);
|
|
44
|
-
|
|
45
|
-
it('should call the progress callback', async () => {
|
|
46
|
-
const progressCallback = vi.fn();
|
|
47
|
-
const baseBlock = new TextEncoder().encode(`${nonce}:`);
|
|
48
|
-
// Use a much harder target to ensure the loop runs long enough
|
|
49
|
-
const hardTarget = '0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
|
|
50
|
-
await solveCpuTargetInline(baseBlock, hardTarget, progressCallback);
|
|
51
|
-
|
|
52
|
-
// Check if the callback was called with a number
|
|
53
|
-
expect(progressCallback).toHaveBeenCalled();
|
|
54
|
-
expect(progressCallback).toHaveBeenCalledWith(expect.any(Number));
|
|
55
|
-
}, 40000); // Increase timeout for harder challenge
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('solveMemory', () => {
|
|
59
|
-
it('should produce a deterministic result for a given seed and difficulty', async () => {
|
|
60
|
-
const seed = 'test-seed';
|
|
61
|
-
const difficulty = 1; // 1MB
|
|
62
|
-
|
|
63
|
-
const solution1 = await solveMemory(seed, difficulty);
|
|
64
|
-
const solution2 = await solveMemory(seed, difficulty);
|
|
65
|
-
|
|
66
|
-
expect(solution1).toBe(solution2);
|
|
67
|
-
expect(solution1).not.toBe(await solveMemory('different-seed', difficulty));
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('solveTsp', () => {
|
|
72
|
-
it('should solve a simple TSP problem', async () => {
|
|
73
|
-
const cities = [{ x: 10, y: 10 }, { x: 90, y: 90 }, { x: 10, y: 90 }, { x: 90, y: 10 }];
|
|
74
|
-
const result = await solveTsp(cities, 400);
|
|
75
|
-
|
|
76
|
-
expect(result.path).toBeInstanceOf(Array);
|
|
77
|
-
expect(result.path.length).toBe(4);
|
|
78
|
-
// The optimal path for a square is ~324. The nearest neighbor should find this.
|
|
79
|
-
expect(result.distance).toBeLessThan(330);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('solveChallenge', () => {
|
|
84
|
-
const nonce = 'challenge-nonce';
|
|
85
|
-
const clientSecret = 'challenge-secret';
|
|
86
|
-
const cpuTarget = '0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
|
|
87
|
-
|
|
88
|
-
it('should solve a "cpu_target" challenge', async () => {
|
|
89
|
-
// The 'cpu_target' case in solveChallenge uses Web Workers, which are not available in Node.js test env.
|
|
90
|
-
// We will test the 'cpu_mem' case which uses the same underlying `solveCpuTargetInline` function.
|
|
91
|
-
// This test is effectively covered by the 'cpu_mem' test below.
|
|
92
|
-
expect(true).toBe(true);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('should solve a "cpu_mem" challenge for an API client', async () => {
|
|
96
|
-
const challenge = {
|
|
97
|
-
type: 'cpu_mem',
|
|
98
|
-
nonce,
|
|
99
|
-
clientSecret,
|
|
100
|
-
cpuTarget,
|
|
101
|
-
memDifficulty: 1,
|
|
102
|
-
// Pour les appels API, le serveur pré-calcule le baseBlock
|
|
103
|
-
// sans l'IP du client, mais avec l'empreinte digitale.
|
|
104
|
-
baseBlock: [...new TextEncoder().encode(`${nonce}:${clientSecret}:`)]
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const solutions = await solveChallenge(challenge, ''); // Le fingerprint est passé en 2e arg
|
|
108
|
-
expect(solutions.rawSolution).toHaveProperty('cpu', expect.any(Number));
|
|
109
|
-
expect(solutions.rawSolution).toHaveProperty('mem', expect.any(Number));
|
|
110
|
-
}, 20000);
|
|
111
|
-
|
|
112
|
-
it('should solve a "cpu_mem_inline" challenge for a browser', async () => {
|
|
113
|
-
const challenge = {
|
|
114
|
-
type: 'cpu_mem_inline',
|
|
115
|
-
nonce,
|
|
116
|
-
clientSecret,
|
|
117
|
-
cpuTarget,
|
|
118
|
-
memDifficulty: 1,
|
|
119
|
-
// Pour le challenge inline, le serveur inclut l'IP dans le baseBlock.
|
|
120
|
-
baseBlock: [...new TextEncoder().encode(`${nonce}:${clientSecret}:`)]
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
const solutions = await solveChallenge(challenge, '');
|
|
124
|
-
expect(solutions.rawSolution).toHaveProperty('cpu', expect.any(Number));
|
|
125
|
-
expect(solutions.rawSolution).toHaveProperty('mem', expect.any(Number));
|
|
126
|
-
}, 20000);
|
|
127
|
-
|
|
128
|
-
it('should solve a "tsp" challenge', async () => {
|
|
129
|
-
const challenge = {
|
|
130
|
-
type: 'tsp',
|
|
131
|
-
cities: [{ x: 0, y: 0 }, { x: 100, y: 100 }],
|
|
132
|
-
targetMaxDistance: 300
|
|
133
|
-
};
|
|
134
|
-
const solutions = await solveChallenge(challenge);
|
|
135
|
-
// Pour le TSP, la solution brute est directement le chemin
|
|
136
|
-
expect(solutions.rawSolution).toEqual([0, 1]);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('should
|
|
140
|
-
const challenge = {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
1
|
+
import {describe, expect, it, vi, beforeEach, afterEach} from 'vitest';
|
|
2
|
+
import {createHash} from 'node:crypto';
|
|
3
|
+
// Import the functions to be tested.
|
|
4
|
+
// Since the inline file doesn't use exports, we can't directly import.
|
|
5
|
+
// Instead, we'll test the ES module version which shares the same logic.
|
|
6
|
+
import {solveChallenge, solveCpuTargetInline, solveMemory, solveTsp} from '../pow.solver.js';
|
|
7
|
+
|
|
8
|
+
describe('Proof-of-Work Solvers', () => {
|
|
9
|
+
|
|
10
|
+
describe('solveCpuTargetInline', () => {
|
|
11
|
+
const nonce = 'test-nonce';
|
|
12
|
+
// A relatively easy target for quick tests (first 16 bits must be zero)
|
|
13
|
+
const targetHex = '0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
|
|
14
|
+
const targetBigInt = BigInt('0x' + targetHex);
|
|
15
|
+
|
|
16
|
+
it('should find a valid CPU solution with a simple base block', async () => {
|
|
17
|
+
// Le `baseBlock` est maintenant un Uint8Array.
|
|
18
|
+
// Le client et le serveur doivent s'accorder sur sa construction.
|
|
19
|
+
// Ici, on simule un challenge simple avec juste le nonce.
|
|
20
|
+
const baseBlock = new TextEncoder().encode(`${nonce}:`);
|
|
21
|
+
const solution = await solveCpuTargetInline(baseBlock, targetHex);
|
|
22
|
+
|
|
23
|
+
// Verification: re-hash the solution and check against the target
|
|
24
|
+
const finalBlock = new Uint8Array([...baseBlock, ...new TextEncoder().encode(String(solution))]);
|
|
25
|
+
const hash = createHash('sha256').update(finalBlock).digest('hex');
|
|
26
|
+
const hashBigInt = BigInt('0x' + hash);
|
|
27
|
+
|
|
28
|
+
expect(hashBigInt).toBeLessThan(targetBigInt);
|
|
29
|
+
}, 20000);
|
|
30
|
+
|
|
31
|
+
it('should find a valid CPU solution with a client secret', async () => {
|
|
32
|
+
const clientSecret = 'my-secret';
|
|
33
|
+
const fingerprint = 'test-fp-string';
|
|
34
|
+
// Le `baseBlock` est maintenant un Uint8Array qui inclut toutes les informations.
|
|
35
|
+
const baseBlock = new TextEncoder().encode(`${nonce}:${clientSecret}:${fingerprint}:`);
|
|
36
|
+
const solution = await solveCpuTargetInline(baseBlock, targetHex);
|
|
37
|
+
|
|
38
|
+
// Verification: re-hash the solution and check against the target
|
|
39
|
+
const finalBlock = new Uint8Array([...baseBlock, ...new TextEncoder().encode(String(solution))]);
|
|
40
|
+
const hash = createHash('sha256').update(finalBlock).digest('hex');
|
|
41
|
+
const hashBigInt = BigInt('0x' + hash);
|
|
42
|
+
expect(hashBigInt).toBeLessThan(targetBigInt);
|
|
43
|
+
}, 20000);
|
|
44
|
+
|
|
45
|
+
it('should call the progress callback', async () => {
|
|
46
|
+
const progressCallback = vi.fn();
|
|
47
|
+
const baseBlock = new TextEncoder().encode(`${nonce}:`);
|
|
48
|
+
// Use a much harder target to ensure the loop runs long enough
|
|
49
|
+
const hardTarget = '0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
|
|
50
|
+
await solveCpuTargetInline(baseBlock, hardTarget, progressCallback);
|
|
51
|
+
|
|
52
|
+
// Check if the callback was called with a number
|
|
53
|
+
expect(progressCallback).toHaveBeenCalled();
|
|
54
|
+
expect(progressCallback).toHaveBeenCalledWith(expect.any(Number));
|
|
55
|
+
}, 40000); // Increase timeout for harder challenge
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe('solveMemory', () => {
|
|
59
|
+
it('should produce a deterministic result for a given seed and difficulty', async () => {
|
|
60
|
+
const seed = 'test-seed';
|
|
61
|
+
const difficulty = 1; // 1MB
|
|
62
|
+
|
|
63
|
+
const solution1 = await solveMemory(seed, difficulty);
|
|
64
|
+
const solution2 = await solveMemory(seed, difficulty);
|
|
65
|
+
|
|
66
|
+
expect(solution1).toBe(solution2);
|
|
67
|
+
expect(solution1).not.toBe(await solveMemory('different-seed', difficulty));
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('solveTsp', () => {
|
|
72
|
+
it('should solve a simple TSP problem', async () => {
|
|
73
|
+
const cities = [{ x: 10, y: 10 }, { x: 90, y: 90 }, { x: 10, y: 90 }, { x: 90, y: 10 }];
|
|
74
|
+
const result = await solveTsp(cities, 400);
|
|
75
|
+
|
|
76
|
+
expect(result.path).toBeInstanceOf(Array);
|
|
77
|
+
expect(result.path.length).toBe(4);
|
|
78
|
+
// The optimal path for a square is ~324. The nearest neighbor should find this.
|
|
79
|
+
expect(result.distance).toBeLessThan(330);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('solveChallenge', () => {
|
|
84
|
+
const nonce = 'challenge-nonce';
|
|
85
|
+
const clientSecret = 'challenge-secret';
|
|
86
|
+
const cpuTarget = '0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
|
|
87
|
+
|
|
88
|
+
it('should solve a "cpu_target" challenge', async () => {
|
|
89
|
+
// The 'cpu_target' case in solveChallenge uses Web Workers, which are not available in Node.js test env.
|
|
90
|
+
// We will test the 'cpu_mem' case which uses the same underlying `solveCpuTargetInline` function.
|
|
91
|
+
// This test is effectively covered by the 'cpu_mem' test below.
|
|
92
|
+
expect(true).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should solve a "cpu_mem" challenge for an API client', async () => {
|
|
96
|
+
const challenge = {
|
|
97
|
+
type: 'cpu_mem',
|
|
98
|
+
nonce,
|
|
99
|
+
clientSecret,
|
|
100
|
+
cpuTarget,
|
|
101
|
+
memDifficulty: 1,
|
|
102
|
+
// Pour les appels API, le serveur pré-calcule le baseBlock
|
|
103
|
+
// sans l'IP du client, mais avec l'empreinte digitale.
|
|
104
|
+
baseBlock: [...new TextEncoder().encode(`${nonce}:${clientSecret}:`)]
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const solutions = await solveChallenge(challenge, ''); // Le fingerprint est passé en 2e arg
|
|
108
|
+
expect(solutions.rawSolution).toHaveProperty('cpu', expect.any(Number));
|
|
109
|
+
expect(solutions.rawSolution).toHaveProperty('mem', expect.any(Number));
|
|
110
|
+
}, 20000);
|
|
111
|
+
|
|
112
|
+
it('should solve a "cpu_mem_inline" challenge for a browser', async () => {
|
|
113
|
+
const challenge = {
|
|
114
|
+
type: 'cpu_mem_inline',
|
|
115
|
+
nonce,
|
|
116
|
+
clientSecret,
|
|
117
|
+
cpuTarget,
|
|
118
|
+
memDifficulty: 1,
|
|
119
|
+
// Pour le challenge inline, le serveur inclut l'IP dans le baseBlock.
|
|
120
|
+
baseBlock: [...new TextEncoder().encode(`${nonce}:${clientSecret}:`)]
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const solutions = await solveChallenge(challenge, '');
|
|
124
|
+
expect(solutions.rawSolution).toHaveProperty('cpu', expect.any(Number));
|
|
125
|
+
expect(solutions.rawSolution).toHaveProperty('mem', expect.any(Number));
|
|
126
|
+
}, 20000);
|
|
127
|
+
|
|
128
|
+
it('should solve a "tsp" challenge', async () => {
|
|
129
|
+
const challenge = {
|
|
130
|
+
type: 'tsp',
|
|
131
|
+
cities: [{ x: 0, y: 0 }, { x: 100, y: 100 }],
|
|
132
|
+
targetMaxDistance: 300
|
|
133
|
+
};
|
|
134
|
+
const solutions = await solveChallenge(challenge);
|
|
135
|
+
// Pour le TSP, la solution brute est directement le chemin
|
|
136
|
+
expect(solutions.rawSolution).toEqual([0, 1]);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should solve a "useful_work_task" with facility location challenge', async () => {
|
|
140
|
+
const challenge = {
|
|
141
|
+
type: 'useful_work_task',
|
|
142
|
+
nonce: 'test-nonce-useful-work',
|
|
143
|
+
usefulWorkTask: {
|
|
144
|
+
problemId: 'facility_location_challenge',
|
|
145
|
+
task: {
|
|
146
|
+
type: 'simulated_annealing_iterations',
|
|
147
|
+
iterations: 10,
|
|
148
|
+
payload: {
|
|
149
|
+
customers: [
|
|
150
|
+
{ x: 100, y: 100 },
|
|
151
|
+
{ x: 200, y: 200 }
|
|
152
|
+
],
|
|
153
|
+
numFacilities: 2,
|
|
154
|
+
bounds: { minX: 0, maxX: 500, minY: 0, maxY: 500 },
|
|
155
|
+
options: {
|
|
156
|
+
fixedCostPerFacility: 1500,
|
|
157
|
+
initialTemperature: 150000,
|
|
158
|
+
coolingRate: 0.99
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const solutions = await solveChallenge(challenge);
|
|
166
|
+
expect(solutions.type).toBe('useful_work_task');
|
|
167
|
+
expect(solutions.nonce).toBe('test-nonce-useful-work');
|
|
168
|
+
expect(solutions.rawSolution.problem_id).toBe('facility_location_challenge');
|
|
169
|
+
expect(solutions.rawSolution.work_result).toBeDefined();
|
|
170
|
+
expect(solutions.rawSolution.work_result.solution).toBeInstanceOf(Array);
|
|
171
|
+
expect(solutions.rawSolution.work_result.solution.length).toBe(2);
|
|
172
|
+
expect(solutions.rawSolution.work_result.energy).toBeLessThan(Infinity);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should throw an error for an unknown challenge type', async () => {
|
|
176
|
+
const challenge = { type: 'unknown' };
|
|
177
|
+
await expect(solveChallenge(challenge)).rejects.toThrow('Unknown challenge type: unknown');
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('WASM Solver Path Integration (Mocked)', () => {
|
|
182
|
+
let mockWasmModule;
|
|
183
|
+
|
|
184
|
+
beforeEach(() => {
|
|
185
|
+
mockWasmModule = {
|
|
186
|
+
_malloc: vi.fn().mockImplementation(() => 1234), // Simule un pointeur mémoire
|
|
187
|
+
_free: vi.fn(),
|
|
188
|
+
HEAPU8: new Uint8Array(10000),
|
|
189
|
+
HEAP8: new Int8Array(10000),
|
|
190
|
+
_solve_cpu_target: vi.fn().mockReturnValue(1337),
|
|
191
|
+
_solve_memory_challenge: vi.fn().mockReturnValue(777)
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// Injecter le module WASM globalement pour simuler le comportement du navigateur
|
|
195
|
+
global.window = {
|
|
196
|
+
wasmModule: mockWasmModule
|
|
197
|
+
};
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
afterEach(() => {
|
|
201
|
+
// Nettoyer l'environnement global après chaque test
|
|
202
|
+
delete global.window;
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('should redirect solveCpuTargetInline to WASM and manage heap memory safely', async () => {
|
|
206
|
+
const baseBlock = new Uint8Array([1, 2, 3, 4]);
|
|
207
|
+
const target = '0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF';
|
|
208
|
+
|
|
209
|
+
const solution = await solveCpuTargetInline(baseBlock, target);
|
|
210
|
+
|
|
211
|
+
// 1. Vérification du résultat natif retourné par le mock
|
|
212
|
+
expect(solution).toBe(1337);
|
|
213
|
+
|
|
214
|
+
// 2. Vérification des allocations et libérations mémoire pour le bloc de base et la cible hexadécimale
|
|
215
|
+
expect(mockWasmModule._malloc).toHaveBeenCalledTimes(2);
|
|
216
|
+
expect(mockWasmModule._free).toHaveBeenCalledTimes(2);
|
|
217
|
+
|
|
218
|
+
// 3. Vérification de l'appel à la fonction C++ exportée
|
|
219
|
+
expect(mockWasmModule._solve_cpu_target).toHaveBeenCalledWith(1234, baseBlock.length, 1234);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should redirect solveMemory to WASM and manage heap memory safely', async () => {
|
|
223
|
+
const seed = 'test-wasm-seed';
|
|
224
|
+
const difficulty = 4; // 4 MB
|
|
225
|
+
|
|
226
|
+
const solution = await solveMemory(seed, difficulty);
|
|
227
|
+
|
|
228
|
+
expect(solution).toBe(777);
|
|
229
|
+
expect(mockWasmModule._malloc).toHaveBeenCalledTimes(1);
|
|
230
|
+
expect(mockWasmModule._free).toHaveBeenCalledTimes(1);
|
|
231
|
+
expect(mockWasmModule._solve_memory_challenge).toHaveBeenCalledWith(1234, difficulty);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
198
234
|
});
|