@cofhe/mock-contracts 0.7.1 → 0.8.0

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.
@@ -0,0 +1,64 @@
1
+ // SPDX-License-Identifier: BSD-3-Clause-Clear
2
+ pragma solidity >=0.8.19 <0.9.0;
3
+
4
+ import { ICoFHEAddressBook } from '@fhenixprotocol/cofhe-contracts/ICofhe.sol';
5
+
6
+ /**
7
+ * @title MockCoFHEAddressBook
8
+ * @notice Mock of the CoFHEAddressBook: maps a TaskManager id to the TaskManager that FHE.sol
9
+ * releases pinned to that id talk to. Deployed to `COFHE_ADDRESS_BOOK` (from FHE.sol)
10
+ * with `hardhat_setCode` / `deployCodeTo`, so no constructor or initializer runs.
11
+ * @dev The production book is an Ownable2Step UUPS proxy; setters here are unrestricted.
12
+ */
13
+ contract MockCoFHEAddressBook is ICoFHEAddressBook {
14
+ mapping(uint256 id => address tm) private taskManagers;
15
+
16
+ /// @notice Emitted when an id is set or unset (`current == address(0)`).
17
+ /// @param id TaskManager id.
18
+ /// @param previous Address the id resolved to before, zero if it was unset.
19
+ /// @param current Address the id resolves to now, zero if it was unset.
20
+ event TaskManagerSet(uint256 indexed id, address indexed previous, address indexed current);
21
+
22
+ /// @notice Returned when an id resolves to nothing.
23
+ /// @param id TaskManager id.
24
+ error TaskManagerNotSet(uint256 id);
25
+
26
+ /// @notice Returned when setting an id to the zero address.
27
+ error InvalidAddress();
28
+
29
+ function exists() public pure returns (bool) {
30
+ return true;
31
+ }
32
+
33
+ /// @notice Resolves an id to its TaskManager.
34
+ /// @param id TaskManager id.
35
+ /// @return tm The TaskManager address; reverts with {TaskManagerNotSet} when unset.
36
+ function getTm(uint256 id) external view returns (address tm) {
37
+ tm = taskManagers[id];
38
+ if (tm == address(0)) {
39
+ revert TaskManagerNotSet(id);
40
+ }
41
+ }
42
+
43
+ /// @notice Points an id at a TaskManager, replacing any previous target.
44
+ /// @param id TaskManager id.
45
+ /// @param tm TaskManager address.
46
+ function setTm(uint256 id, address tm) external {
47
+ if (tm == address(0)) {
48
+ revert InvalidAddress();
49
+ }
50
+ emit TaskManagerSet(id, taskManagers[id], tm);
51
+ taskManagers[id] = tm;
52
+ }
53
+
54
+ /// @notice Retires an id: every FHE.sol build pinned to it reverts from then on.
55
+ /// @param id TaskManager id.
56
+ function unsetTm(uint256 id) external {
57
+ address previous = taskManagers[id];
58
+ if (previous == address(0)) {
59
+ revert TaskManagerNotSet(id);
60
+ }
61
+ emit TaskManagerSet(id, previous, address(0));
62
+ delete taskManagers[id];
63
+ }
64
+ }
@@ -263,22 +263,63 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
263
263
  return true;
264
264
  }
265
265
 
266
- function sendEventCreated(uint256 ctHash, string memory operation, uint256[] memory inputs) private {
267
- if (inputs.length == 1 || opIs(operation, FunctionId.cast)) {
268
- emit TaskCreated(ctHash, operation, inputs[0], 0, 0);
266
+ error OnlySelf();
269
267
 
270
- // NOTE: MOCK
271
- MOCK_unaryOperation(ctHash, operation, inputs[0]);
272
- } else if (inputs.length == 2) {
273
- emit TaskCreated(ctHash, operation, inputs[0], inputs[1], 0);
268
+ function sendEventCreated(
269
+ uint256 ctHash,
270
+ FunctionId funcId,
271
+ string memory operation,
272
+ uint256[] memory inputs
273
+ ) private {
274
+ uint8 arity = (inputs.length == 1 || funcId == FunctionId.cast) ? 1 : (inputs.length == 2 ? 2 : 3);
274
275
 
275
- // NOTE: MOCK
276
- MOCK_twoInputOperation(ctHash, operation, inputs[0], inputs[1]);
276
+ if (arity == 1) {
277
+ emit TaskCreated(ctHash, operation, inputs[0], 0, 0);
278
+ } else if (arity == 2) {
279
+ emit TaskCreated(ctHash, operation, inputs[0], inputs[1], 0);
277
280
  } else {
278
281
  emit TaskCreated(ctHash, operation, inputs[0], inputs[1], inputs[2]);
282
+ }
279
283
 
280
- // NOTE: MOCK
281
- MOCK_threeInputOperation(ctHash, operation, inputs[0], inputs[1], inputs[2]);
284
+ // NOTE: MOCK - plaintext replication is mock-only work that doesn't exist in the real
285
+ // task manager, so (under forge, when enabled) it runs with gas metering paused; when
286
+ // metered (hardhat) its cost is reported via MockGasConsumed instead.
287
+ (MockGasMode mode, uint256 startGas) = _mockGasTrackStart();
288
+ if (mode != MockGasMode.PAUSED_BY_MOCK) {
289
+ // MEASURE, or the caller's test already paused metering (nothing of ours to leak
290
+ // on revert in either case).
291
+ _mockDispatch(ctHash, funcId, inputs, arity);
292
+ _mockGasTrackEnd(mode, startGas);
293
+ return;
294
+ }
295
+
296
+ // External self-call so a revert inside the mock op can be caught and gas metering
297
+ // resumed before bubbling the original error - otherwise the paused state leaks into
298
+ // the rest of the test and every later call reports ~0 gas. The extra call itself
299
+ // runs unmetered.
300
+ try this.MOCK_dispatchOperation(ctHash, funcId, inputs, arity) {
301
+ _mockGasTrackEnd(mode, startGas);
302
+ } catch (bytes memory err) {
303
+ _mockGasTrackEnd(mode, startGas);
304
+ assembly ('memory-safe') {
305
+ revert(add(err, 0x20), mload(err))
306
+ }
307
+ }
308
+ }
309
+
310
+ /// @dev Trampoline for `sendEventCreated`'s try/catch; not part of the mocked interface.
311
+ function MOCK_dispatchOperation(uint256 ctHash, FunctionId funcId, uint256[] calldata inputs, uint8 arity) external {
312
+ if (msg.sender != address(this)) revert OnlySelf();
313
+ _mockDispatch(ctHash, funcId, inputs, arity);
314
+ }
315
+
316
+ function _mockDispatch(uint256 ctHash, FunctionId funcId, uint256[] memory inputs, uint8 arity) private {
317
+ if (arity == 1) {
318
+ MOCK_unaryOperation(ctHash, funcId, inputs[0]);
319
+ } else if (arity == 2) {
320
+ MOCK_twoInputOperation(ctHash, funcId, inputs[0], inputs[1]);
321
+ } else {
322
+ MOCK_threeInputOperation(ctHash, funcId, inputs[0], inputs[1], inputs[2]);
282
323
  }
283
324
  }
284
325
 
@@ -299,12 +340,18 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
299
340
  // );
300
341
  // }
301
342
 
302
- // NOTE: MOCK
343
+ // NOTE: MOCK - the real task manager only emits a task event here and the result lands
344
+ // in a later transaction; storing it synchronously is mock-only work. Only the cheap
345
+ // existence check runs before the tracked block (so an InputNotInMockStorage revert
346
+ // can't leak paused gas metering); the read itself is mock-only and stays inside.
347
+ MOCK_verifyKeyInStorage(ctHash);
348
+ (MockGasMode mode, uint256 startGas) = _mockGasTrackStart();
303
349
  _decryptResultReady[ctHash] = true;
304
350
  _decryptResult[ctHash] = _get(ctHash);
305
351
 
306
352
  uint64 asyncOffset = uint64((block.timestamp % 10) + 1);
307
353
  _decryptResultReadyTimestamp[ctHash] = uint64(block.timestamp) + asyncOffset;
354
+ _mockGasTrackEnd(mode, startGas);
308
355
  }
309
356
 
310
357
  function getDecryptResult(uint256 ctHash) public view returns (uint256) {
@@ -399,9 +446,11 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
399
446
  }
400
447
  }
401
448
 
402
- function validateInputs(uint256[] memory encryptedHashes, FunctionId funcId) internal view {
403
- string memory functionName = Utils.functionIdToString(funcId);
404
-
449
+ function validateInputs(
450
+ uint256[] memory encryptedHashes,
451
+ FunctionId funcId,
452
+ string memory functionName
453
+ ) internal view {
405
454
  if (encryptedHashes.length == 0) {
406
455
  if (!isPlaintextOperation(funcId)) {
407
456
  revert InvalidOperationInputs(functionName);
@@ -455,19 +504,20 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
455
504
  if (funcId == FunctionId.random) {
456
505
  revert RandomFunctionNotSupported();
457
506
  }
507
+ string memory operation = Utils.functionIdToString(funcId);
458
508
  uint256 inputsLength = encryptedHashes.length + extraInputs.length;
459
509
  if (inputsLength > 3) {
460
- revert TooManyInputs(Utils.functionIdToString(funcId), inputsLength, 3);
510
+ revert TooManyInputs(operation, inputsLength, 3);
461
511
  }
462
512
 
463
- validateInputs(encryptedHashes, funcId);
513
+ validateInputs(encryptedHashes, funcId, operation);
464
514
  uint256[] memory inputs = TMCommon.combineInputs(encryptedHashes, extraInputs);
465
515
 
466
516
  int32 securityZone = getSecurityZone(funcId, encryptedHashes, extraInputs);
467
517
  uint256 ctHash = TMCommon.calcPlaceholderKey(returnType, securityZone, inputs, funcId);
468
518
 
469
519
  acl.allowTransient(ctHash, msg.sender, address(this));
470
- sendEventCreated(ctHash, Utils.functionIdToString(funcId), inputs);
520
+ sendEventCreated(ctHash, funcId, operation, inputs);
471
521
 
472
522
  return ctHash;
473
523
  }
@@ -611,7 +661,7 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
611
661
  acl.allow(ctHash, account, msg.sender);
612
662
 
613
663
  // NOTE: MOCK
614
- MOCK_logAllow(account == msg.sender ? 'FHE.allowThis' : 'FHE.allow', ctHash, account);
664
+ MOCK_trackedLogAllow(account == msg.sender ? 'FHE.allowThis' : 'FHE.allow', ctHash, account);
615
665
  }
616
666
  }
617
667
 
@@ -620,7 +670,7 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
620
670
  acl.allowGlobal(ctHash, msg.sender);
621
671
 
622
672
  // NOTE: MOCK
623
- MOCK_logAllow('FHE.allowGlobal', ctHash, msg.sender);
673
+ MOCK_trackedLogAllow('FHE.allowGlobal', ctHash, msg.sender);
624
674
  }
625
675
  }
626
676
 
@@ -629,7 +679,7 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
629
679
  acl.allowTransient(ctHash, account, msg.sender);
630
680
 
631
681
  // NOTE: MOCK
632
- MOCK_logAllow('FHE.allowTransient', ctHash, account);
682
+ MOCK_trackedLogAllow('FHE.allowTransient', ctHash, account);
633
683
  }
634
684
  }
635
685
 
@@ -640,7 +690,7 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
640
690
  acl.allowForDecryption(hashes, msg.sender);
641
691
 
642
692
  // NOTE: MOCK
643
- MOCK_logAllow('FHE.allowForDecryption', ctHash, msg.sender);
693
+ MOCK_trackedLogAllow('FHE.allowForDecryption', ctHash, msg.sender);
644
694
  }
645
695
  }
646
696
 
@@ -655,14 +705,14 @@ contract MockTaskManager is ITaskManager, MockCoFHE {
655
705
  acl.shareCtHash(ctHash, msg.sender, receiver);
656
706
 
657
707
  // NOTE: MOCK
658
- MOCK_logAllow('FHE.share', ctHash, receiver);
708
+ MOCK_trackedLogAllow('FHE.share', ctHash, receiver);
659
709
  }
660
710
 
661
711
  function receiveCtHash(uint256 ctHash, address expectedSharer) external {
662
712
  acl.receiveCtHash(ctHash, expectedSharer, msg.sender);
663
713
 
664
714
  // NOTE: MOCK
665
- MOCK_logAllow('FHE.receive', ctHash, expectedSharer);
715
+ MOCK_trackedLogAllow('FHE.receive', ctHash, expectedSharer);
666
716
  }
667
717
 
668
718
  /// @dev Per-input message hash used by batch verification:
@@ -3,7 +3,7 @@
3
3
 
4
4
  pragma solidity >=0.8.19 <0.9.0;
5
5
 
6
- import { TASK_MANAGER_ADDRESS } from '@fhenixprotocol/cofhe-contracts/FHE.sol';
6
+ import { Common } from '@fhenixprotocol/cofhe-contracts/FHE.sol';
7
7
  import { EncryptedInput } from '@fhenixprotocol/cofhe-contracts/ICofhe.sol';
8
8
  import { MockTaskManager } from './MockTaskManager.sol';
9
9
 
@@ -104,7 +104,7 @@ contract MockZkVerifier {
104
104
  }
105
105
 
106
106
  function insertCtHash(uint256 ctHash, uint256 value) public {
107
- MockTaskManager(TASK_MANAGER_ADDRESS).MOCK_setInEuintKey(ctHash, value);
107
+ MockTaskManager(address(Common.tm())).MOCK_setInEuintKey(ctHash, value);
108
108
  salt += 1;
109
109
  }
110
110