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

KS-129: Implement modify DON #13242

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
128 changes: 91 additions & 37 deletions contracts/src/v0.8/keystone/CapabilityRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
/// @param signer The node's signer address
event NodeUpdated(bytes32 p2pId, uint256 nodeOperatorId, bytes32 signer);

/// @notice This event is emitted when a DON's config is set
/// @param donId The ID of the DON the config was set for
/// @param configCount The number of times the DON has been
/// configured
event ConfigSet(uint32 donId, uint32 configCount);

/// @notice This event is emitted when a new DON is created
/// @param donId The ID of the newly created DON
/// @param isPublic True if the newly created DON is public
Expand All @@ -186,6 +192,11 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
/// @param donId The ID of the removed DON
event DONRemoved(uint32 donId);

/// @notice This event is emitted when a new DON is created
/// @param donId The ID of the updated DON
/// @param isPublic True if the updated DON is public
event DONUpdated(uint256 donId, bool isPublic);
cds95 marked this conversation as resolved.
Show resolved Hide resolved

/// @notice This error is emitted when a DON does not exist
/// @param donId The ID of the nonexistent DON
error DONDoesNotExist(uint32 donId);
Expand Down Expand Up @@ -550,46 +561,34 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
bool isPublic
) external onlyOwner {
uint32 id = s_donId;

s_dons[id].id = id;
s_dons[id].isPublic = isPublic;

uint32 configCount = 1;

DONCapabilityConfig storage donCapabilityConfig = s_dons[id].config[configCount];

for (uint256 i; i < nodes.length; ++i) {
bytes32 nodeP2PId = nodes[i];
if (donCapabilityConfig.nodes.contains(nodeP2PId)) revert DuplicateDONNode(id, nodeP2PId);

donCapabilityConfig.nodes.add(nodeP2PId);
}

for (uint256 i; i < capabilityConfigurations.length; ++i) {
CapabilityConfiguration calldata configuration = capabilityConfigurations[i];
bytes32 capabilityId = configuration.capabilityId;

if (!s_hashedCapabilityIds.contains(capabilityId)) revert CapabilityDoesNotExist(capabilityId);
if (s_deprecatedHashedCapabilityIds.contains(capabilityId)) revert CapabilityIsDeprecated(capabilityId);

if (donCapabilityConfig.capabilityConfigs[capabilityId].length > 0)
revert DuplicateDONCapability(id, capabilityId);

for (uint256 j; j < nodes.length; ++j) {
bytes32 nodeP2PId = nodes[j];
if (!s_nodes[nodeP2PId].supportedCapabilityIds[s_nodes[nodeP2PId].configCount].contains(capabilityId))
revert NodeDoesNotSupportCapability(nodeP2PId, capabilityId);
}

donCapabilityConfig.capabilityIds.push(capabilityId);
donCapabilityConfig.capabilityConfigs[capabilityId] = configuration.config;
}

s_dons[id].configCount = configCount;
uint32 configCount = 1; // Initialize config count to start at 1
_setDONConfig(id, configCount, nodes, capabilityConfigurations, isPublic);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32 configCount = 1; // Initialize config count to start at 1
_setDONConfig(id, configCount, nodes, capabilityConfigurations, isPublic);
_setDONConfig(id, 1, nodes, capabilityConfigurations, isPublic);

++s_donId;
emit DONAdded(id, isPublic);
}

/// @notice Updates a DON's configuration. This allows
/// the admin to reconfigure the list of capabilities supported
/// by the DON, the list of nodes that make up the DON as well
/// as whether or not the DON can accept external workflows
/// @param nodes The nodes making up the DON
/// @param capabilityConfigurations The list of configurations for the
/// capabilities supported by the DON
/// @param isPublic True if the DON is can accept external workflows
function updateDON(
uint32 donId,
bytes32[] calldata nodes,
CapabilityConfiguration[] calldata capabilityConfigurations,
bool isPublic
) external onlyOwner {
uint32 configCount = s_dons[donId].configCount;
if (configCount == 0) revert DONDoesNotExist(donId);
_setDONConfig(donId, ++configCount, nodes, capabilityConfigurations, isPublic);
++s_donId;
emit DONUpdated(donId, isPublic);
}

/// @notice Removes DONs from the Capability Registry
/// @param donIds The IDs of the DON to be removed
function removeDONs(uint32[] calldata donIds) external onlyOwner {
Expand All @@ -607,12 +606,13 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
/// @notice Gets DON's data
/// @param donId The DON ID
/// @return uint32 The DON ID
/// @return uint32 The DON's config count
/// @return bool True if the DON is public
/// @return bytes32[] The list of node P2P IDs that are in the DON
/// @return CapabilityConfiguration[] The list of capability configurations supported by the DON
function getDON(
uint32 donId
) external view returns (uint32, bool, bytes32[] memory, CapabilityConfiguration[] memory) {
) external view returns (uint32, uint32, bool, bytes32[] memory, CapabilityConfiguration[] memory) {
uint32 configCount = s_dons[donId].configCount;

DONCapabilityConfig storage donCapabilityConfig = s_dons[donId].config[configCount];
Expand All @@ -627,7 +627,13 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
});
}

return (s_dons[donId].id, s_dons[donId].isPublic, donCapabilityConfig.nodes.values(), capabilityConfigurations);
return (
s_dons[donId].id,
configCount,
s_dons[donId].isPublic,
donCapabilityConfig.nodes.values(),
capabilityConfigurations
);
}

/// @notice Returns the DON specific configuration for a capability
Expand All @@ -638,4 +644,52 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
uint32 configCount = s_dons[donId].configCount;
return s_dons[donId].config[configCount].capabilityConfigs[capabilityId];
}

/// @notice Sets the configuration for a DON
/// @param donId The ID of the DON to set the configuration for
/// @param configCount The number of times the DON has been configured
/// @param nodes The nodes making up the DON
/// @param capabilityConfigurations The list of configurations for the
/// capabilities supported by the DON
/// @param isPublic True if the DON is can accept external workflows
function _setDONConfig(
uint32 donId,
uint32 configCount,
bytes32[] calldata nodes,
CapabilityConfiguration[] calldata capabilityConfigurations,
bool isPublic
) internal {
s_dons[donId].isPublic = isPublic;

DONCapabilityConfig storage donCapabilityConfig = s_dons[donId].config[configCount];
for (uint256 i; i < nodes.length; ++i) {
Copy link
Contributor Author

@cds95 cds95 May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking a bit on how to optimize this. Currently the code blindly updates the DON's nodes and supported capability configs even if the function parameters are the same as what's already in storage. One idea I had was to store the hash of nodes and capabilityConfigs and compare them against the hash of the params passed in.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a ticket to test this out during the gas optimization stage?

bytes32 nodeP2PId = nodes[i];
if (donCapabilityConfig.nodes.contains(nodeP2PId)) revert DuplicateDONNode(donId, nodeP2PId);

donCapabilityConfig.nodes.add(nodeP2PId);
}

for (uint256 i; i < capabilityConfigurations.length; ++i) {
CapabilityConfiguration calldata configuration = capabilityConfigurations[i];
bytes32 capabilityId = configuration.capabilityId;

if (!s_hashedCapabilityIds.contains(capabilityId)) revert CapabilityDoesNotExist(capabilityId);
if (s_deprecatedHashedCapabilityIds.contains(capabilityId)) revert CapabilityIsDeprecated(capabilityId);

if (donCapabilityConfig.capabilityConfigs[capabilityId].length > 0)
revert DuplicateDONCapability(donId, capabilityId);

for (uint256 j; j < nodes.length; ++j) {
bytes32 nodeP2PId = nodes[j];
if (!s_nodes[nodeP2PId].supportedCapabilityIds[s_nodes[nodeP2PId].configCount].contains(capabilityId))
revert NodeDoesNotSupportCapability(nodeP2PId, capabilityId);
}

donCapabilityConfig.capabilityIds.push(capabilityId);
donCapabilityConfig.capabilityConfigs[capabilityId] = configuration.config;
}

s_dons[donId].configCount = configCount;
emit ConfigSet(donId, configCount);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import {CapabilityRegistry} from "../CapabilityRegistry.sol";

contract CapabilityRegistry_AddDONTest is BaseTest {
event DONAdded(uint256 donId, bool isPublic);
event ConfigSet(uint32 donId, uint32 configCount);

uint32 private constant DON_ID = 1;
uint32 private constant TEST_NODE_OPERATOR_ONE_ID = 0;
uint256 private constant TEST_NODE_OPERATOR_TWO_ID = 1;
bytes32 private constant INVALID_P2P_ID = bytes32("fake-p2p");
Expand Down Expand Up @@ -158,22 +160,26 @@ contract CapabilityRegistry_AddDONTest is BaseTest {
});

vm.expectEmit(true, true, true, true, address(s_capabilityRegistry));
emit DONAdded(1, true);
emit ConfigSet(DON_ID, 1);
vm.expectEmit(true, true, true, true, address(s_capabilityRegistry));
emit DONAdded(DON_ID, true);
s_capabilityRegistry.addDON(nodes, capabilityConfigs, true);

(
uint32 id,
uint32 configCount,
bool isPublic,
bytes32[] memory donNodes,
CapabilityRegistry.CapabilityConfiguration[] memory donCapabilityConfigs
) = s_capabilityRegistry.getDON(1);
assertEq(id, 1);
) = s_capabilityRegistry.getDON(DON_ID);
assertEq(id, DON_ID);
assertEq(configCount, 1);
assertEq(isPublic, true);
assertEq(donCapabilityConfigs.length, 1);
assertEq(donCapabilityConfigs.length, capabilityConfigs.length);
assertEq(donCapabilityConfigs[0].capabilityId, s_basicHashedCapabilityId);
assertEq(s_capabilityRegistry.getDONCapabilityConfig(1, s_basicHashedCapabilityId), CONFIG);
assertEq(s_capabilityRegistry.getDONCapabilityConfig(DON_ID, s_basicHashedCapabilityId), CONFIG);

assertEq(donNodes.length, 1);
assertEq(donNodes.length, nodes.length);
assertEq(donNodes[0], P2P_ID);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,13 @@ contract CapabilityRegistry_RemoveDONsTest is BaseTest {

(
uint32 id,
uint32 configCount,
bool isPublic,
bytes32[] memory donNodes,
CapabilityRegistry.CapabilityConfiguration[] memory donCapabilityConfigs
) = s_capabilityRegistry.getDON(DON_ID);
assertEq(id, 0);
assertEq(configCount, 0);
assertEq(isPublic, false);
assertEq(donCapabilityConfigs.length, 0);
assertEq(s_capabilityRegistry.getDONCapabilityConfig(DON_ID, s_basicHashedCapabilityId), bytes(""));
Expand Down
Loading
Loading