From 6305380287992f5b088e9f4f5cc3c9e75ad69e49 Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 5 Sep 2024 12:22:40 -0400 Subject: [PATCH 1/2] feat: store ciphernode in an incremental merkle tree --- .../interfaces/ICiphernodeRegistry.sol | 22 +++++++- .../registry/CiphernodeRegistryOwnable.sol | 53 +++++++++++++------ 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/packages/evm/contracts/interfaces/ICiphernodeRegistry.sol b/packages/evm/contracts/interfaces/ICiphernodeRegistry.sol index 2a01199f..6a48f70a 100644 --- a/packages/evm/contracts/interfaces/ICiphernodeRegistry.sol +++ b/packages/evm/contracts/interfaces/ICiphernodeRegistry.sol @@ -22,10 +22,28 @@ interface ICiphernodeRegistry { event EnclaveSet(address indexed enclave); /// @notice This event MUST be emitted when a ciphernode is added to the registry. - event CiphernodeAdded(address indexed node); + /// @param node Address of the ciphernode. + /// @param index Index of the ciphernode in the registry. + /// @param numNodes Number of ciphernodes in the registry. + /// @param size Size of the registry. + event CiphernodeAdded( + address indexed node, + uint256 index, + uint256 numNodes, + uint256 size + ); /// @notice This event MUST be emitted when a ciphernode is removed from the registry. - event CiphernodeRemoved(address indexed node); + /// @param node Address of the ciphernode. + /// @param index Index of the ciphernode in the registry. + /// @param numNodes Number of ciphernodes in the registry. + /// @param size Size of the registry. + event CiphernodeRemoved( + address indexed node, + uint256 index, + uint256 numNodes, + uint256 size + ); function isCiphernodeEligible(address ciphernode) external returns (bool); diff --git a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index 6793fdf2..19a9b693 100644 --- a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -6,8 +6,15 @@ import { IRegistryFilter } from "../interfaces/IRegistryFilter.sol"; import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { + InternalLeanIMT, + LeanIMTData, + PoseidonT3 +} from "@zk-kit/lean-imt.sol/InternalLeanIMT.sol"; contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { + using InternalLeanIMT for LeanIMTData; + //////////////////////////////////////////////////////////// // // // Storage Variables // @@ -15,8 +22,8 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { //////////////////////////////////////////////////////////// address public enclave; - - mapping(address ciphernode => bool isEnabled) public isEnabled; + uint256 public numCiphernodes; + LeanIMTData public ciphernodes; mapping(uint256 e3Id => IRegistryFilter filter) public requests; mapping(uint256 e3Id => bytes publicKey) public publicKeys; @@ -91,13 +98,6 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { // only to be published by the filter require(address(requests[e3Id]) == msg.sender, CommitteeDoesNotExist()); - // for (uint256 i = 0; i < ciphernodes.length; i++) { - // require( - // isEnabled[ciphernodes[i]] == true, - // CiphernodeNotEnabled(ciphernodes[i]) - // ); - // } - publicKeys[e3Id] = publicKey; emit CommitteePublished(e3Id, publicKey); } @@ -114,17 +114,36 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { } function addCiphernode(address node) external onlyOwner { - isEnabled[node] = true; - emit CiphernodeAdded(node); + uint256 ciphernode = uint256(bytes32(bytes20(node))); + ciphernodes._insert(ciphernode); + numCiphernodes++; + emit CiphernodeAdded( + node, + ciphernodes._indexOf(ciphernode), + numCiphernodes, + ciphernodes.size + ); } - function removeCiphernode(address node) external onlyOwner { - isEnabled[node] = false; - emit CiphernodeRemoved(node); + function removeCiphernode( + address node, + uint256[] calldata siblingNodes + ) external onlyOwner { + uint256 ciphernode = uint256(bytes32(bytes20(node))); + ciphernodes._remove(ciphernode, siblingNodes); + uint256 index = ciphernodes._indexOf(ciphernode); + numCiphernodes--; + emit CiphernodeAdded( + node, + ciphernodes._indexOf(ciphernode), + numCiphernodes, + ciphernodes.size + ); + emit CiphernodeRemoved(node, index, numCiphernodes, ciphernodes.size); } function isCiphernodeEligible(address node) external view returns (bool) { - return isEnabled[node]; + return isEnabled(node); } //////////////////////////////////////////////////////////// @@ -139,4 +158,8 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { publicKey = publicKeys[e3Id]; require(publicKey.length > 0, CommitteeNotPublished()); } + + function isEnabled(address node) public view returns (bool) { + return ciphernodes._has(uint256(bytes32(bytes20(node)))); + } } From 01a7b6b81b846639503d9ec8b8a215a15185b3cb Mon Sep 17 00:00:00 2001 From: Auryn Macmillan Date: Thu, 5 Sep 2024 12:58:49 -0400 Subject: [PATCH 2/2] feat: make roots easily accessible --- .../contracts/registry/CiphernodeRegistryOwnable.sol | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol index 19a9b693..96c4c54b 100644 --- a/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol +++ b/packages/evm/contracts/registry/CiphernodeRegistryOwnable.sol @@ -26,6 +26,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { LeanIMTData public ciphernodes; mapping(uint256 e3Id => IRegistryFilter filter) public requests; + mapping(uint256 e3Id => uint256 root) public roots; mapping(uint256 e3Id => bytes publicKey) public publicKeys; //////////////////////////////////////////////////////////// @@ -84,6 +85,7 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { CommitteeAlreadyRequested() ); requests[e3Id] = IRegistryFilter(filter); + roots[e3Id] = root(); IRegistryFilter(filter).requestCommittee(e3Id, threshold); emit CommitteeRequested(e3Id, filter, threshold); @@ -162,4 +164,12 @@ contract CiphernodeRegistryOwnable is ICiphernodeRegistry, OwnableUpgradeable { function isEnabled(address node) public view returns (bool) { return ciphernodes._has(uint256(bytes32(bytes20(node)))); } + + function root() public view returns (uint256) { + return (ciphernodes._root()); + } + + function rootAt(uint256 e3Id) public view returns (uint256) { + return roots[e3Id]; + } }