Skip to content

Commit

Permalink
Add getCapabilities to the CapabilityRegistry (#13031)
Browse files Browse the repository at this point in the history
* Add getCapabilities

* Fix comments
  • Loading branch information
DeividasK committed Apr 30, 2024
1 parent e21be2a commit 04b42f1
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 40 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-cats-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#internal
5 changes: 5 additions & 0 deletions contracts/.changeset/bright-dingos-attend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": patch
---

#internal
16 changes: 16 additions & 0 deletions contracts/src/v0.8/keystone/CapabilityRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,22 @@ contract CapabilityRegistry is OwnerIsCreator, TypeAndVersionInterface {
return s_capabilities[capabilityID];
}

/// @notice Returns all capabilities. This operation will copy capabilities
/// to memory, which can be quite expensive. This is designed to mostly be
/// used by view accessors that are queried without any gas fees.
/// @return Capability[] An array of capabilities
function getCapabilities() external view returns (Capability[] memory) {
bytes32[] memory capabilityIds = s_capabilityIds.values();
Capability[] memory capabilities = new Capability[](capabilityIds.length);

for (uint256 i; i < capabilityIds.length; ++i) {
bytes32 capabilityId = capabilityIds[i];
capabilities[i] = getCapability(capabilityId);
}

return capabilities;
}

/// @notice This functions returns a Capability ID packed into a bytes32 for cheaper access
/// @return bytes32 A unique identifier for the capability
function getCapabilityID(bytes32 capabilityType, bytes32 version) public pure returns (bytes32) {
Expand Down
16 changes: 16 additions & 0 deletions contracts/src/v0.8/keystone/test/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@ import {CapabilityRegistry} from "../CapabilityRegistry.sol";
contract BaseTest is Test, Constants {
CapabilityRegistry internal s_capabilityRegistry;
CapabilityConfigurationContract internal s_capabilityConfigurationContract;
CapabilityRegistry.Capability internal s_basicCapability;
CapabilityRegistry.Capability internal s_capabilityWithConfigurationContract;

function setUp() public virtual {
vm.startPrank(ADMIN);
s_capabilityRegistry = new CapabilityRegistry();
s_capabilityConfigurationContract = new CapabilityConfigurationContract();

s_basicCapability = CapabilityRegistry.Capability({
capabilityType: "data-streams-reports",
version: "1.0.0",
responseType: CapabilityRegistry.CapabilityResponseType.REPORT,
configurationContract: address(0)
});

s_capabilityWithConfigurationContract = CapabilityRegistry.Capability({
capabilityType: "read-ethereum-mainnet-gas-price",
version: "1.0.2",
responseType: CapabilityRegistry.CapabilityResponseType.OBSERVATION_IDENTICAL,
configurationContract: address(s_capabilityConfigurationContract)
});
}

function _getNodeOperators() internal view returns (CapabilityRegistry.NodeOperator[] memory) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,83 +7,67 @@ import {CapabilityConfigurationContract} from "./mocks/CapabilityConfigurationCo
import {CapabilityRegistry} from "../CapabilityRegistry.sol";

contract CapabilityRegistry_AddCapabilityTest is BaseTest {
CapabilityRegistry.Capability private basicCapability =
CapabilityRegistry.Capability({
capabilityType: "data-streams-reports",
version: "1.0.0",
responseType: CapabilityRegistry.CapabilityResponseType.REPORT,
configurationContract: address(0)
});

CapabilityRegistry.Capability private capabilityWithConfigurationContract =
CapabilityRegistry.Capability({
capabilityType: "read-ethereum-mainnet-gas-price",
version: "1.0.2",
responseType: CapabilityRegistry.CapabilityResponseType.OBSERVATION_IDENTICAL,
configurationContract: address(s_capabilityConfigurationContract)
});

function test_RevertWhen_CalledByNonAdmin() public {
changePrank(STRANGER);

vm.expectRevert("Only callable by owner");
s_capabilityRegistry.addCapability(basicCapability);
s_capabilityRegistry.addCapability(s_basicCapability);
}

function test_RevertWhen_CapabilityExists() public {
// Successfully add the capability the first time
s_capabilityRegistry.addCapability(basicCapability);
s_capabilityRegistry.addCapability(s_basicCapability);

// Try to add the same capability again
vm.expectRevert(CapabilityRegistry.CapabilityAlreadyExists.selector);
s_capabilityRegistry.addCapability(basicCapability);
s_capabilityRegistry.addCapability(s_basicCapability);
}

function test_RevertWhen_ConfigurationContractNotDeployed() public {
address nonExistentContract = address(1);
capabilityWithConfigurationContract.configurationContract = nonExistentContract;
s_capabilityWithConfigurationContract.configurationContract = nonExistentContract;

vm.expectRevert(
abi.encodeWithSelector(
CapabilityRegistry.InvalidCapabilityConfigurationContractInterface.selector,
nonExistentContract
)
);
s_capabilityRegistry.addCapability(capabilityWithConfigurationContract);
s_capabilityRegistry.addCapability(s_capabilityWithConfigurationContract);
}

function test_RevertWhen_ConfigurationContractDoesNotMatchInterface() public {
CapabilityRegistry contractWithoutERC165 = new CapabilityRegistry();

vm.expectRevert();
capabilityWithConfigurationContract.configurationContract = address(contractWithoutERC165);
s_capabilityRegistry.addCapability(capabilityWithConfigurationContract);
s_capabilityWithConfigurationContract.configurationContract = address(contractWithoutERC165);
s_capabilityRegistry.addCapability(s_capabilityWithConfigurationContract);
}

function test_AddCapability_NoConfigurationContract() public {
s_capabilityRegistry.addCapability(basicCapability);
s_capabilityRegistry.addCapability(s_basicCapability);

bytes32 capabilityId = s_capabilityRegistry.getCapabilityID(bytes32("data-streams-reports"), bytes32("1.0.0"));
CapabilityRegistry.Capability memory storedCapability = s_capabilityRegistry.getCapability(capabilityId);

assertEq(storedCapability.capabilityType, basicCapability.capabilityType);
assertEq(storedCapability.version, basicCapability.version);
assertEq(uint256(storedCapability.responseType), uint256(basicCapability.responseType));
assertEq(storedCapability.configurationContract, basicCapability.configurationContract);
assertEq(storedCapability.capabilityType, s_basicCapability.capabilityType);
assertEq(storedCapability.version, s_basicCapability.version);
assertEq(uint256(storedCapability.responseType), uint256(s_basicCapability.responseType));
assertEq(storedCapability.configurationContract, s_basicCapability.configurationContract);
}

function test_AddCapability_WithConfiguration() public {
s_capabilityRegistry.addCapability(capabilityWithConfigurationContract);
s_capabilityRegistry.addCapability(s_capabilityWithConfigurationContract);

bytes32 capabilityId = s_capabilityRegistry.getCapabilityID(
bytes32(capabilityWithConfigurationContract.capabilityType),
bytes32(capabilityWithConfigurationContract.version)
bytes32(s_capabilityWithConfigurationContract.capabilityType),
bytes32(s_capabilityWithConfigurationContract.version)
);
CapabilityRegistry.Capability memory storedCapability = s_capabilityRegistry.getCapability(capabilityId);

assertEq(storedCapability.capabilityType, capabilityWithConfigurationContract.capabilityType);
assertEq(storedCapability.version, capabilityWithConfigurationContract.version);
assertEq(uint256(storedCapability.responseType), uint256(capabilityWithConfigurationContract.responseType));
assertEq(storedCapability.configurationContract, capabilityWithConfigurationContract.configurationContract);
assertEq(storedCapability.capabilityType, s_capabilityWithConfigurationContract.capabilityType);
assertEq(storedCapability.version, s_capabilityWithConfigurationContract.version);
assertEq(uint256(storedCapability.responseType), uint256(s_capabilityWithConfigurationContract.responseType));
assertEq(storedCapability.configurationContract, s_capabilityWithConfigurationContract.configurationContract);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {BaseTest} from "./BaseTest.t.sol";
import {CapabilityRegistry} from "../CapabilityRegistry.sol";

contract CapabilityRegistry_GetCapabilitiesTest is BaseTest {
function test_ReturnsCapabilities() public {
s_capabilityRegistry.addCapability(s_basicCapability);
s_capabilityRegistry.addCapability(s_capabilityWithConfigurationContract);

CapabilityRegistry.Capability[] memory capabilities = s_capabilityRegistry.getCapabilities();

assertEq(capabilities.length, 2);

assertEq(capabilities[0].capabilityType, "data-streams-reports");
assertEq(capabilities[0].version, "1.0.0");
assertEq(uint256(capabilities[0].responseType), uint256(CapabilityRegistry.CapabilityResponseType.REPORT));
assertEq(capabilities[0].configurationContract, address(0));

assertEq(capabilities[1].capabilityType, "read-ethereum-mainnet-gas-price");
assertEq(capabilities[1].version, "1.0.2");
assertEq(
uint256(capabilities[1].responseType),
uint256(CapabilityRegistry.CapabilityResponseType.OBSERVATION_IDENTICAL)
);
assertEq(capabilities[1].configurationContract, address(s_capabilityConfigurationContract));
}
}
2 changes: 0 additions & 2 deletions contracts/src/v0.8/keystone/test/Constants.t.sol
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {Test} from "forge-std/Test.sol";

contract Constants {
address internal ADMIN = address(1);
address internal STRANGER = address(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ contract CapabilityConfigurationContract is ICapabilityConfiguration, ERC165 {
function getCapabilityConfiguration(uint256 donId) external view returns (bytes memory configuration) {
return s_donConfiguration[donId];
}

function supportsInterface(bytes4 interfaceId) public pure override returns (bool) {
return interfaceId == this.getCapabilityConfiguration.selector;
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
GETH_VERSION: 1.13.8
forwarder: ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.abi ../../../contracts/solc/v0.8.19/KeystoneForwarder/KeystoneForwarder.bin b4c900aae9e022f01abbac7993d41f93912247613ac6270b0c4da4ef6f2016e3
keystone_capability_registry: ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.abi ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.bin 5f801185084a6d6bcc08e0a37574d80f5092bc0dcd40808e9e04804064db0a56
keystone_capability_registry: ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.abi ../../../contracts/solc/v0.8.19/CapabilityRegistry/CapabilityRegistry.bin ae9e077854854fa066746eaa354324c7dac2a13bc38b81a66c856fddfc3b79bf
ocr3_capability: ../../../contracts/solc/v0.8.19/OCR3Capability/OCR3Capability.abi ../../../contracts/solc/v0.8.19/OCR3Capability/OCR3Capability.bin 9dcbdf55bd5729ba266148da3f17733eb592c871c2108ccca546618628fd9ad2

0 comments on commit 04b42f1

Please sign in to comment.