Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Registry Spec #2

Merged
merged 7 commits into from
Jun 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions packages/evm/contracts/Enclave.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ contract Enclave is IEnclave, OwnableUpgradeable {
////////////////////////////////////////////////////////////

function request(
address[] memory pools, // TODO: should we allow for multiple pools?
address filter,
uint32[2] calldata threshold,
// TODO: do we also need a start block/time? Would it be possible to have computations where inputs are
//published before the request is made? This kind of assumes the cypher nodes have already been selected
Expand Down Expand Up @@ -163,21 +163,21 @@ contract Enclave is IEnclave, OwnableUpgradeable {
inputValidator: inputValidator,
outputVerifier: outputVerifier,
committeePublicKey: hex"",
inputs: new bytes[](0),
ciphertextOutput: hex"",
plaintextOutput: hex""
});
e3s[e3Id] = e3;

require(
cyphernodeRegistry.selectCommittee(e3Id, pools, threshold),
cyphernodeRegistry.requestCommittee(e3Id, filter, threshold),
CommitteeSelectionFailed()
);
// TODO: validate that the selected pool accepts both the computation and execution modules.

emit E3Requested(
e3Id,
e3s[e3Id],
pools,
filter,
computationModule,
executionModule
);
Expand All @@ -189,14 +189,13 @@ contract Enclave is IEnclave, OwnableUpgradeable {
E3 memory e3 = getE3(e3Id);
require(e3.expiration == 0, E3AlreadyActivated(e3Id));

bytes memory committeePublicKey = cyphernodeRegistry
.getCommitteePublicKey(e3Id);
bytes memory publicKey = cyphernodeRegistry.committeePublicKey(e3Id);
// Note: This check feels weird
require(committeePublicKey.length > 0, CommitteeSelectionFailed());
require(publicKey.length > 0, CommitteeSelectionFailed());

// TODO: this should be based on the duration requested, not the current max duration.
e3s[e3Id].expiration = block.timestamp + maxDuration;
e3s[e3Id].committeePublicKey = committeePublicKey;
e3s[e3Id].committeePublicKey = publicKey;

emit E3Activated(e3Id, e3.expiration, e3.committeePublicKey);

Expand All @@ -219,7 +218,8 @@ contract Enclave is IEnclave, OwnableUpgradeable {
bytes memory input;
(input, success) = e3.inputValidator.validate(msg.sender, data);
require(success, InvalidInput());
// TODO: do we need to store or accumulate the inputs? Probably yes.
// TODO: probably better to accumulate inputs, rather than just dumping them in storage.
e3s[e3Id].inputs.push(input);
emit InputPublished(e3Id, input);
}

Expand Down
54 changes: 28 additions & 26 deletions packages/evm/contracts/interfaces/ICyphernodeRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,59 @@ pragma solidity >=0.8.26;
interface ICyphernodeRegistry {
/// @notice This event MUST be emitted when a committee is selected for an E3.
/// @param e3Id ID of the E3 for which the committee was selected.
/// @param pools Addresses of the pools of nodes from which the committee was selected.
/// @param filter Address of the contract that will coordinate committee selection.
/// @param threshold The M/N threshold for the committee.
event CommitteeRequested(
uint256 indexed e3Id,
address[] pools,
address filter,
uint32[2] threshold
);

/// @notice This event MUST be emitted when a committee is selected for an E3.
/// @param e3Id ID of the E3 for which the committee was selected.
/// @param nodes Addresses of the nodes in the committee.
/// @param merkleRoots Merkle roots of the nodes in the committee.
/// @param publicKey Public key of the committee.
event CommitteeSelected(
uint256 indexed e3Id,
address[] nodes,
bytes32[] merkleRoots,
bytes publicKey
);

/// @notice This event MUST be emitted when a node is added to the registry.
/// @param nodeId ID of the node.
/// @param node Address of the node.
event NodeAdded(uint256 indexed nodeId, address indexed node);

/// @notice This event MUST be emitted when a node is removed from the registry.
/// @param nodeId ID of the node.
/// @param node Address of the node.
event NodeRemoved(uint256 indexed nodeId, address indexed node);
event CommitteePublished(uint256 indexed e3Id, bytes publicKey);

/// @notice This event MUST be emitted when `encalve` is set.
/// @param enclave Address of the enclave contract.
event EnclaveSet(address indexed enclave);

/// @notice This function should be called by the Enclave contract to select a node committee.
/// @notice This event MUST be emitted when a cyphernode is added to the registry.
event CyphernodeAdded(address indexed node);

/// @notice This event MUST be emitted when a cyphernode is removed from the registry.
event CyphernodeRemoved(address indexed node);

function isCyphernodeEligible(address cyphernode) external returns (bool);

/// @notice Initiates the committee selection process for a specified E3.
/// @dev This function MUST revert when not called by the Enclave contract.
/// @param e3Id ID of the E3 for which to select the committee.
/// @param pools IDs of the pool of nodes from which to select the committee.
/// @param filter The address of the filter responsible for the committee selection process.
/// @param threshold The M/N threshold for the committee.
/// @return success True if committee selection was successfully initiated.
function selectCommittee(
function requestCommittee(
uint256 e3Id,
address[] memory pools,
address filter,
uint32[2] calldata threshold
) external returns (bool success);

/// @notice Publishes the public key resulting from the committee selection process.
/// @dev This function MUST revert if not called by the previously selected filter.
/// @param e3Id ID of the E3 for which to select the committee.
/// @param publicKey The public key generated by the selected committee.
function publishCommittee(
uint256 e3Id,
bytes calldata proof,
bytes calldata publicKey
) external;

/// @notice This function should be called by the Enclave contract to get the public key of a committee.
/// @dev This function MUST revert if no committee has been requested for the given E3.
/// @dev This function MUST revert if the committee has not yet published a public key.
/// @param e3Id ID of the E3 for which to get the committee public key.
/// @return publicKey The public key of the committee.
function getCommitteePublicKey(
function committeePublicKey(
uint256 e3Id
) external view returns (bytes memory publicKey);
) external view returns (bytes memory);
}
1 change: 1 addition & 0 deletions packages/evm/contracts/interfaces/IE3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct E3 {
IInputValidator inputValidator;
IOutputVerifier outputVerifier;
bytes committeePublicKey;
bytes[] inputs;
bytes ciphertextOutput;
bytes plaintextOutput;
}
8 changes: 4 additions & 4 deletions packages/evm/contracts/interfaces/IEnclave.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ interface IEnclave {
/// @notice This event MUST be emitted when an Encrypted Execution Environment (E3) is successfully requested.
/// @param e3Id ID of the E3.
/// @param e3 Details of the E3.
/// @param pool Address of the pool of nodes from which the Cypher Node committee was selected.
/// @param filter Address of the pool of nodes from which the Cypher Node committee was selected.
/// @param computationModule Address of the Computation module selected.
/// @param executionModule Address of the execution module selected.
event E3Requested(
uint256 e3Id,
E3 e3,
address[] pool,
address filter,
IComputationModule indexed computationModule,
IExecutionModule indexed executionModule
);
Expand Down Expand Up @@ -87,7 +87,7 @@ interface IEnclave {

/// @notice This function should be called to request a computation within an Encrypted Execution Environment (E3).
/// @dev This function MUST emit the E3Requested event.
/// @param pools IDs of the pool of nodes from which to select the committee.
/// @param filter IDs of the pool of nodes from which to select the committee.
/// @param threshold The M/N threshold for the committee.
/// @param duration The duration of the computation in seconds.
/// @param computationModule Address of the computation module.
Expand All @@ -97,7 +97,7 @@ interface IEnclave {
/// @return e3Id ID of the E3.
/// @return e3 The E3 struct.
function request(
address[] memory pools,
address filter,
uint32[2] calldata threshold,
uint256 duration,
IComputationModule computationModule,
Expand Down
7 changes: 0 additions & 7 deletions packages/evm/contracts/interfaces/INodePool.sol

This file was deleted.

9 changes: 9 additions & 0 deletions packages/evm/contracts/interfaces/IRegistryFilter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.26;

interface IRegistryFilter {
function requestCommittee(
uint256 e3Id,
uint32[2] calldata threshold
) external returns (bool success);
}
101 changes: 50 additions & 51 deletions packages/evm/contracts/registry/CyphernodeRegistryOwnable.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,12 @@
pragma solidity >=0.8.26;

import { ICyphernodeRegistry } from "../interfaces/ICyphernodeRegistry.sol";
import { IRegistryFilter } from "../interfaces/IRegistryFilter.sol";
import {
OwnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable {
struct Committee {
address[] nodes;
uint32[2] threshold;
address[] pools;
bytes32[] merkleRoots;
bytes publicKey;
}

struct Node {
bool eligible;
// Number of duties the node has not yet completed.
// Incremented each time a duty is added, decremented each time a duty is completed.
uint256 outstandingDuties;
}

////////////////////////////////////////////////////////////
// //
// Storage Variables //
Expand All @@ -30,19 +16,22 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable {

address public enclave;

mapping(uint256 e3 => Committee committee) public committees;
mapping(address nodeId => Node node) public nodes;
mapping(address cyphernode => bool isEnabled) public isEnabled;

mapping(uint256 e3Id => IRegistryFilter filter) public requests;
mapping(uint256 e3Id => bytes publicKey) public publicKeys;

////////////////////////////////////////////////////////////
// //
// Errors //
// //
////////////////////////////////////////////////////////////

error CommitteeAlreadyExists();
error CommitteeAlreadyRequested();
error CommitteeAlreadyPublished();
error CommitteeDoesNotExist();
error NoPublicKeyPublished();
error CommitteeNotPublished();
error CyphernodeNotEnabled(address node);
error OnlyEnclave();

////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -78,36 +67,39 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable {
// //
////////////////////////////////////////////////////////////

function selectCommittee(
function requestCommittee(
uint256 e3Id,
address[] memory pools,
address filter,
uint32[2] calldata threshold
) external onlyEnclave returns (bool success) {
Committee storage committee = committees[e3Id];
require(committee.threshold.length == 0, CommitteeAlreadyExists());
committee.threshold = threshold;
committee.pools = pools;
success = true;
require(
requests[e3Id] == IRegistryFilter(address(0)),
CommitteeAlreadyRequested()
);
requests[e3Id] = IRegistryFilter(filter);

emit CommitteeRequested(e3Id, pools, threshold);
IRegistryFilter(filter).requestCommittee(e3Id, threshold);
emit CommitteeRequested(e3Id, filter, threshold);
success = true;
}

function publishCommittee(
uint256 e3Id,
address[] memory _nodes,
bytes32[] memory merkleRoots,
bytes memory publicKey
) external onlyOwner {
Committee storage committee = committees[e3Id];
require(
keccak256(committee.publicKey) == keccak256(hex""),
CommitteeAlreadyPublished()
);
committee.nodes = _nodes;
committee.merkleRoots = merkleRoots;
committee.publicKey = publicKey;

emit CommitteeSelected(e3Id, _nodes, merkleRoots, publicKey);
bytes calldata,
bytes calldata publicKey
) external {
// only to be published by the filter
require(address(requests[e3Id]) == msg.sender, CommitteeDoesNotExist());

// for (uint256 i = 0; i < cyphernodes.length; i++) {
// require(
// isEnabled[cyphernodes[i]] == true,
// CyphernodeNotEnabled(cyphernodes[i])
// );
// }

publicKeys[e3Id] = publicKey;
emit CommitteePublished(e3Id, publicKey);
}

////////////////////////////////////////////////////////////
Expand All @@ -121,23 +113,30 @@ contract CyphernodeRegistryOwnable is ICyphernodeRegistry, OwnableUpgradeable {
emit EnclaveSet(_enclave);
}

function addCyphernode(address node) external onlyOwner {
isEnabled[node] = true;
emit CyphernodeAdded(node);
}

function removeCyphernode(address node) external onlyOwner {
isEnabled[node] = false;
emit CyphernodeRemoved(node);
}

function isCyphernodeEligible(address node) external view returns (bool) {
return isEnabled[node];
}

////////////////////////////////////////////////////////////
// //
// Get Functions //
// //
////////////////////////////////////////////////////////////

function getCommitteePublicKey(
function committeePublicKey(
uint256 e3Id
) external view returns (bytes memory publicKey) {
publicKey = committees[e3Id].publicKey;
require(publicKey.length > 0, NoPublicKeyPublished());
}

function getCommittee(
uint256 e3Id
) external view returns (Committee memory committee) {
committee = committees[e3Id];
require(committees[e3Id].threshold.length > 0, CommitteeDoesNotExist());
publicKey = publicKeys[e3Id];
require(publicKey.length > 0, CommitteeNotPublished());
}
}
Loading
Loading