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

contracts/ccip/capability: per (donId, pluginType) active config indexes #1488

Merged
merged 4 commits into from
Oct 4, 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
30 changes: 15 additions & 15 deletions contracts/gas-snapshots/ccip.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -59,28 +59,28 @@ CCIPHome_applyChainConfigUpdates:test_applyChainConfigUpdates_nodeNotInRegistry_
CCIPHome_applyChainConfigUpdates:test_applyChainConfigUpdates_removeChainConfigs_Success() (gas: 270824)
CCIPHome_applyChainConfigUpdates:test_applyChainConfigUpdates_selectorNotFound_Reverts() (gas: 14952)
CCIPHome_applyChainConfigUpdates:test_getPaginatedCCIPHomes_Success() (gas: 370980)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_DONIdMismatch_reverts() (gas: 27108)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_DONIdMismatch_reverts() (gas: 27137)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_InnerCallReverts_reverts() (gas: 11783)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_InvalidSelector_reverts() (gas: 11038)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_OnlyCapabilitiesRegistryCanCall_reverts() (gas: 26121)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_success() (gas: 1412263)
CCIPHome_constructor:test_constructor_CapabilitiesRegistryAddressZero_reverts() (gas: 63866)
CCIPHome_constructor:test_constructor_success() (gas: 3498390)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_OnlyCapabilitiesRegistryCanCall_reverts() (gas: 26150)
CCIPHome_beforeCapabilityConfigSet:test_beforeCapabilityConfigSet_success() (gas: 1436726)
CCIPHome_constructor:test_constructor_CapabilitiesRegistryAddressZero_reverts() (gas: 63878)
CCIPHome_constructor:test_constructor_success() (gas: 3521034)
CCIPHome_constructor:test_getCapabilityConfiguration_success() (gas: 9173)
CCIPHome_constructor:test_supportsInterface_success() (gas: 9865)
CCIPHome_getAllConfigs:test_getAllConfigs_success() (gas: 2735455)
CCIPHome_getConfigDigests:test_getConfigDigests_success() (gas: 2513909)
CCIPHome_getAllConfigs:test_getAllConfigs_success() (gas: 2765282)
CCIPHome_getConfigDigests:test_getConfigDigests_success() (gas: 2539724)
CCIPHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_CanOnlySelfCall_reverts() (gas: 9110)
CCIPHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_ConfigDigestMismatch_reverts() (gas: 21877)
CCIPHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_NoOpStateTransitionNotAllowed_reverts() (gas: 8796)
CCIPHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_success() (gas: 2556754)
CCIPHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_ConfigDigestMismatch_reverts() (gas: 23052)
CCIPHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_NoOpStateTransitionNotAllowed_reverts() (gas: 8818)
CCIPHome_promoteCandidateAndRevokeActive:test_promoteCandidateAndRevokeActive_multiplePlugins_success() (gas: 5096112)
CCIPHome_revokeCandidate:test_revokeCandidate_CanOnlySelfCall_reverts() (gas: 9068)
CCIPHome_revokeCandidate:test_revokeCandidate_ConfigDigestMismatch_reverts() (gas: 18421)
CCIPHome_revokeCandidate:test_revokeCandidate_ConfigDigestMismatch_reverts() (gas: 19128)
CCIPHome_revokeCandidate:test_revokeCandidate_RevokingZeroDigestNotAllowed_reverts() (gas: 8773)
CCIPHome_revokeCandidate:test_revokeCandidate_success() (gas: 29506)
CCIPHome_setCandidate:test_setCandidate_CanOnlySelfCall_reverts() (gas: 19022)
CCIPHome_setCandidate:test_setCandidate_ConfigDigestMismatch_reverts() (gas: 1385010)
CCIPHome_setCandidate:test_setCandidate_success() (gas: 1355245)
CCIPHome_revokeCandidate:test_revokeCandidate_success() (gas: 30676)
CCIPHome_setCandidate:test_setCandidate_CanOnlySelfCall_reverts() (gas: 19051)
CCIPHome_setCandidate:test_setCandidate_ConfigDigestMismatch_reverts() (gas: 1388198)
CCIPHome_setCandidate:test_setCandidate_success() (gas: 1357740)
CommitStore_constructor:test_Constructor_Success() (gas: 2855567)
CommitStore_isUnpausedAndRMNHealthy:test_RMN_Success() (gas: 73954)
CommitStore_report:test_InvalidIntervalMinLargerThanMax_Revert() (gas: 28739)
Expand Down
35 changes: 18 additions & 17 deletions contracts/src/v0.8/ccip/capability/CCIPHome.sol
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,10 @@ contract CCIPHome is OwnerIsCreator, ITypeAndVersion, ICapabilityConfiguration,
s_configs;

/// @notice The total number of configs ever set, used for generating the version of the configs.
/// @dev Used to ensure unique digests across all configurations.
uint32 private s_currentVersion = 0;
/// @notice The index of the active config.
uint32 private s_activeConfigIndex = 0;
/// @notice The index of the active config on a per-don and per-plugin basis.
mapping(uint32 donId => mapping(Internal.OCRPluginType pluginType => uint32)) private s_activeConfigIndexes;

/// @notice Constructor for the CCIPHome contract takes in the address of the capabilities registry. This address
/// is the only allowed caller to mutate the configuration through beforeCapabilityConfigSet.
Expand Down Expand Up @@ -263,21 +264,21 @@ contract CCIPHome is OwnerIsCreator, ITypeAndVersion, ICapabilityConfiguration,
Internal.OCRPluginType pluginType
) public view returns (bytes32 activeConfigDigest, bytes32 candidateConfigDigest) {
return (
s_configs[donId][pluginType][_getActiveIndex()].configDigest,
s_configs[donId][pluginType][_getCandidateIndex()].configDigest
s_configs[donId][pluginType][_getActiveIndex(donId, pluginType)].configDigest,
s_configs[donId][pluginType][_getCandidateIndex(donId, pluginType)].configDigest
);
}

/// @notice Returns the active config digest for for a given key.
/// @param donId The key of the plugin to get the config digests for.
function getActiveDigest(uint32 donId, Internal.OCRPluginType pluginType) public view returns (bytes32) {
return s_configs[donId][pluginType][_getActiveIndex()].configDigest;
return s_configs[donId][pluginType][_getActiveIndex(donId, pluginType)].configDigest;
}

/// @notice Returns the candidate config digest for for a given key.
/// @param donId The key of the plugin to get the config digests for.
function getCandidateDigest(uint32 donId, Internal.OCRPluginType pluginType) public view returns (bytes32) {
return s_configs[donId][pluginType][_getCandidateIndex()].configDigest;
return s_configs[donId][pluginType][_getCandidateIndex(donId, pluginType)].configDigest;
}

/// @notice The offchain code can use this to fetch an old config which might still be in use by some remotes. Use
Expand Down Expand Up @@ -310,12 +311,12 @@ contract CCIPHome is OwnerIsCreator, ITypeAndVersion, ICapabilityConfiguration,
uint32 donId,
Internal.OCRPluginType pluginType
) external view returns (VersionedConfig memory activeConfig, VersionedConfig memory candidateConfig) {
VersionedConfig memory storedActiveConfig = s_configs[donId][pluginType][_getActiveIndex()];
VersionedConfig memory storedActiveConfig = s_configs[donId][pluginType][_getActiveIndex(donId, pluginType)];
if (storedActiveConfig.configDigest != ZERO_DIGEST) {
activeConfig = storedActiveConfig;
}

VersionedConfig memory storedCandidateConfig = s_configs[donId][pluginType][_getCandidateIndex()];
VersionedConfig memory storedCandidateConfig = s_configs[donId][pluginType][_getCandidateIndex(donId, pluginType)];
if (storedCandidateConfig.configDigest != ZERO_DIGEST) {
candidateConfig = storedCandidateConfig;
}
Expand Down Expand Up @@ -353,7 +354,7 @@ contract CCIPHome is OwnerIsCreator, ITypeAndVersion, ICapabilityConfiguration,
uint32 newVersion = ++s_currentVersion;
newConfigDigest = _calculateConfigDigest(donId, pluginType, abi.encode(config), newVersion);

VersionedConfig storage existingConfig = s_configs[donId][pluginType][_getCandidateIndex()];
VersionedConfig storage existingConfig = s_configs[donId][pluginType][_getCandidateIndex(donId, pluginType)];
existingConfig.configDigest = newConfigDigest;
existingConfig.version = newVersion;
existingConfig.config = config;
Expand All @@ -373,7 +374,7 @@ contract CCIPHome is OwnerIsCreator, ITypeAndVersion, ICapabilityConfiguration,
revert RevokingZeroDigestNotAllowed();
}

uint256 candidateConfigIndex = _getCandidateIndex();
uint256 candidateConfigIndex = _getCandidateIndex(donId, pluginType);
if (s_configs[donId][pluginType][candidateConfigIndex].configDigest != configDigest) {
revert ConfigDigestMismatch(s_configs[donId][pluginType][candidateConfigIndex].configDigest, configDigest);
}
Expand All @@ -400,19 +401,19 @@ contract CCIPHome is OwnerIsCreator, ITypeAndVersion, ICapabilityConfiguration,
revert NoOpStateTransitionNotAllowed();
}

uint256 candidateConfigIndex = _getCandidateIndex();
uint256 candidateConfigIndex = _getCandidateIndex(donId, pluginType);
if (s_configs[donId][pluginType][candidateConfigIndex].configDigest != digestToPromote) {
revert ConfigDigestMismatch(s_configs[donId][pluginType][candidateConfigIndex].configDigest, digestToPromote);
}

VersionedConfig storage activeConfig = s_configs[donId][pluginType][_getActiveIndex()];
VersionedConfig storage activeConfig = s_configs[donId][pluginType][_getActiveIndex(donId, pluginType)];
if (activeConfig.configDigest != digestToRevoke) {
revert ConfigDigestMismatch(activeConfig.configDigest, digestToRevoke);
}

delete activeConfig.configDigest;

s_activeConfigIndex ^= 1;
s_activeConfigIndexes[donId][pluginType] ^= 1;
if (digestToRevoke != ZERO_DIGEST) {
emit ActiveConfigRevoked(digestToRevoke);
}
Expand Down Expand Up @@ -444,12 +445,12 @@ contract CCIPHome is OwnerIsCreator, ITypeAndVersion, ICapabilityConfiguration,
);
}

function _getActiveIndex() private view returns (uint32) {
return s_activeConfigIndex;
function _getActiveIndex(uint32 donId, Internal.OCRPluginType pluginType) private view returns (uint32) {
return s_activeConfigIndexes[donId][pluginType];
}

function _getCandidateIndex() private view returns (uint32) {
return s_activeConfigIndex ^ 1;
function _getCandidateIndex(uint32 donId, Internal.OCRPluginType pluginType) private view returns (uint32) {
return s_activeConfigIndexes[donId][pluginType] ^ 1;
}

// ================================================================
Expand Down
75 changes: 49 additions & 26 deletions contracts/src/v0.8/ccip/test/capability/CCIPHome.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ contract CCIPHomeTest is Test {
);
}

function _getBaseConfig() internal pure returns (CCIPHome.OCR3Config memory) {
function _getBaseConfig(Internal.OCRPluginType pluginType) internal pure returns (CCIPHome.OCR3Config memory) {
CCIPHome.OCR3Node[] memory nodes = new CCIPHome.OCR3Node[](4);
for (uint256 i = 0; i < nodes.length; i++) {
nodes[i] = CCIPHome.OCR3Node({
Expand All @@ -87,7 +87,7 @@ contract CCIPHomeTest is Test {
}

return CCIPHome.OCR3Config({
pluginType: Internal.OCRPluginType.Commit,
pluginType: pluginType,
chainSelector: DEFAULT_CHAIN_SELECTOR,
FRoleDON: 1,
offchainConfigVersion: 98765,
Expand Down Expand Up @@ -131,8 +131,10 @@ contract CCIPHome_beforeCapabilityConfigSet is CCIPHomeTest {

function test_beforeCapabilityConfigSet_success() public {
// first set a config
bytes memory callData =
abi.encodeCall(CCIPHome.setCandidate, (DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(), ZERO_DIGEST));
bytes memory callData = abi.encodeCall(
CCIPHome.setCandidate,
(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(Internal.OCRPluginType.Commit), ZERO_DIGEST)
);

vm.expectCall(address(s_ccipHome), callData);

Expand All @@ -149,8 +151,10 @@ contract CCIPHome_beforeCapabilityConfigSet is CCIPHomeTest {
s_ccipHome.beforeCapabilityConfigSet(new bytes32[](0), callData, 0, DEFAULT_DON_ID);

// Then set a new config
callData =
abi.encodeCall(CCIPHome.setCandidate, (DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(), ZERO_DIGEST));
callData = abi.encodeCall(
CCIPHome.setCandidate,
(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(Internal.OCRPluginType.Commit), ZERO_DIGEST)
);

vm.expectCall(address(s_ccipHome), callData);

Expand All @@ -174,8 +178,10 @@ contract CCIPHome_beforeCapabilityConfigSet is CCIPHomeTest {
}

function test_beforeCapabilityConfigSet_OnlyCapabilitiesRegistryCanCall_reverts() public {
bytes memory callData =
abi.encodeCall(CCIPHome.setCandidate, (DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(), ZERO_DIGEST));
bytes memory callData = abi.encodeCall(
CCIPHome.setCandidate,
(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(Internal.OCRPluginType.Commit), ZERO_DIGEST)
);

vm.stopPrank();

Expand All @@ -194,8 +200,10 @@ contract CCIPHome_beforeCapabilityConfigSet is CCIPHomeTest {
function test_beforeCapabilityConfigSet_DONIdMismatch_reverts() public {
uint32 wrongDonId = DEFAULT_DON_ID + 1;

bytes memory callData =
abi.encodeCall(CCIPHome.setCandidate, (DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(), ZERO_DIGEST));
bytes memory callData = abi.encodeCall(
CCIPHome.setCandidate,
(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(Internal.OCRPluginType.Commit), ZERO_DIGEST)
);

vm.expectRevert(abi.encodeWithSelector(CCIPHome.DONIdMismatch.selector, DEFAULT_DON_ID, wrongDonId));
s_ccipHome.beforeCapabilityConfigSet(new bytes32[](0), callData, 0, wrongDonId);
Expand All @@ -215,7 +223,7 @@ contract CCIPHome_getConfigDigests is CCIPHomeTest {
assertEq(activeDigest, ZERO_DIGEST);
assertEq(candidateDigest, ZERO_DIGEST);

CCIPHome.OCR3Config memory config = _getBaseConfig();
CCIPHome.OCR3Config memory config = _getBaseConfig(Internal.OCRPluginType.Commit);
bytes32 firstDigest = s_ccipHome.setCandidate(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, config, ZERO_DIGEST);

(activeDigest, candidateDigest) = s_ccipHome.getConfigDigests(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE);
Expand All @@ -241,7 +249,7 @@ contract CCIPHome_getConfigDigests is CCIPHomeTest {

contract CCIPHome_getAllConfigs is CCIPHomeTest {
function test_getAllConfigs_success() public {
CCIPHome.OCR3Config memory config = _getBaseConfig();
CCIPHome.OCR3Config memory config = _getBaseConfig(Internal.OCRPluginType.Commit);
bytes32 firstDigest = s_ccipHome.setCandidate(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, config, ZERO_DIGEST);

(CCIPHome.VersionedConfig memory activeConfig, CCIPHome.VersionedConfig memory candidateConfig) =
Expand Down Expand Up @@ -273,7 +281,7 @@ contract CCIPHome_getAllConfigs is CCIPHomeTest {

contract CCIPHome_setCandidate is CCIPHomeTest {
function test_setCandidate_success() public {
CCIPHome.OCR3Config memory config = _getBaseConfig();
CCIPHome.OCR3Config memory config = _getBaseConfig(Internal.OCRPluginType.Commit);
CCIPHome.VersionedConfig memory versionedConfig =
CCIPHome.VersionedConfig({version: 1, config: config, configDigest: ZERO_DIGEST});

Expand All @@ -294,7 +302,7 @@ contract CCIPHome_setCandidate is CCIPHomeTest {
}

function test_setCandidate_ConfigDigestMismatch_reverts() public {
CCIPHome.OCR3Config memory config = _getBaseConfig();
CCIPHome.OCR3Config memory config = _getBaseConfig(Internal.OCRPluginType.Commit);

bytes32 digest = s_ccipHome.setCandidate(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, config, ZERO_DIGEST);

Expand All @@ -311,15 +319,17 @@ contract CCIPHome_setCandidate is CCIPHomeTest {
vm.stopPrank();

vm.expectRevert(CCIPHome.CanOnlySelfCall.selector);
s_ccipHome.setCandidate(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(), ZERO_DIGEST);
s_ccipHome.setCandidate(
DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, _getBaseConfig(Internal.OCRPluginType.Commit), ZERO_DIGEST
);
}
}

contract CCIPHome_revokeCandidate is CCIPHomeTest {
// Sets two configs
function setUp() public virtual override {
super.setUp();
CCIPHome.OCR3Config memory config = _getBaseConfig();
CCIPHome.OCR3Config memory config = _getBaseConfig(Internal.OCRPluginType.Commit);
bytes32 digest = s_ccipHome.setCandidate(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, config, ZERO_DIGEST);
s_ccipHome.promoteCandidateAndRevokeActive(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, digest, ZERO_DIGEST);

Expand Down Expand Up @@ -373,36 +383,49 @@ contract CCIPHome_revokeCandidate is CCIPHomeTest {
}

contract CCIPHome_promoteCandidateAndRevokeActive is CCIPHomeTest {
function test_promoteCandidateAndRevokeActive_success() public {
CCIPHome.OCR3Config memory config = _getBaseConfig();
bytes32 firstConfigToPromote = s_ccipHome.setCandidate(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, config, ZERO_DIGEST);
function test_promoteCandidateAndRevokeActive_multiplePlugins_success() public {
promoteCandidateAndRevokeActive(Internal.OCRPluginType.Commit);
promoteCandidateAndRevokeActive(Internal.OCRPluginType.Execution);

// check that the two plugins have only active configs and no candidates.
(bytes32 activeDigest, bytes32 candidateDigest) =
s_ccipHome.getConfigDigests(DEFAULT_DON_ID, Internal.OCRPluginType.Commit);
assertTrue(activeDigest != ZERO_DIGEST);
assertEq(candidateDigest, ZERO_DIGEST);

(activeDigest, candidateDigest) = s_ccipHome.getConfigDigests(DEFAULT_DON_ID, Internal.OCRPluginType.Execution);
assertTrue(activeDigest != ZERO_DIGEST);
assertEq(candidateDigest, ZERO_DIGEST);
}

function promoteCandidateAndRevokeActive(Internal.OCRPluginType pluginType) public {
CCIPHome.OCR3Config memory config = _getBaseConfig(pluginType);
bytes32 firstConfigToPromote = s_ccipHome.setCandidate(DEFAULT_DON_ID, pluginType, config, ZERO_DIGEST);

vm.expectEmit();
emit CCIPHome.ConfigPromoted(firstConfigToPromote);

s_ccipHome.promoteCandidateAndRevokeActive(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, firstConfigToPromote, ZERO_DIGEST);
s_ccipHome.promoteCandidateAndRevokeActive(DEFAULT_DON_ID, pluginType, firstConfigToPromote, ZERO_DIGEST);

// Assert the active digest is updated and the candidate digest is set to zero
(bytes32 activeDigest, bytes32 candidateDigest) = s_ccipHome.getConfigDigests(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE);
(bytes32 activeDigest, bytes32 candidateDigest) = s_ccipHome.getConfigDigests(DEFAULT_DON_ID, pluginType);
assertEq(activeDigest, firstConfigToPromote);
assertEq(candidateDigest, ZERO_DIGEST);

// Set a new candidate to promote over a non-zero active config.
config.offchainConfig = abi.encode("new_offchainConfig_config");
bytes32 secondConfigToPromote = s_ccipHome.setCandidate(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, config, ZERO_DIGEST);
bytes32 secondConfigToPromote = s_ccipHome.setCandidate(DEFAULT_DON_ID, pluginType, config, ZERO_DIGEST);

vm.expectEmit();
emit CCIPHome.ActiveConfigRevoked(firstConfigToPromote);

vm.expectEmit();
emit CCIPHome.ConfigPromoted(secondConfigToPromote);

s_ccipHome.promoteCandidateAndRevokeActive(
DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE, secondConfigToPromote, firstConfigToPromote
);
s_ccipHome.promoteCandidateAndRevokeActive(DEFAULT_DON_ID, pluginType, secondConfigToPromote, firstConfigToPromote);

(CCIPHome.VersionedConfig memory activeConfig, CCIPHome.VersionedConfig memory candidateConfig) =
s_ccipHome.getAllConfigs(DEFAULT_DON_ID, DEFAULT_PLUGIN_TYPE);
s_ccipHome.getAllConfigs(DEFAULT_DON_ID, pluginType);
assertEq(activeConfig.configDigest, secondConfigToPromote);
assertEq(candidateConfig.configDigest, ZERO_DIGEST);
assertEq(keccak256(abi.encode(activeConfig.config)), keccak256(abi.encode(config)));
Expand Down
Loading
Loading