Skip to content

Commit

Permalink
add more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
RensR committed Sep 19, 2024
1 parent 606981c commit 36720d2
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 7 deletions.
20 changes: 20 additions & 0 deletions contracts/gas-snapshots/ccip.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,26 @@ PingPong_plumbing:test_OutOfOrderExecution_Success() (gas: 20310)
PingPong_plumbing:test_Pausing_Success() (gas: 17810)
PingPong_startPingPong:test_StartPingPong_With_OOO_Success() (gas: 162091)
PingPong_startPingPong:test_StartPingPong_With_Sequenced_Ordered_Success() (gas: 181509)
RMNHome_promoteSecondary:test_promoteSecondary_ConfigDigestMismatch_reverts() (gas: 18909)
RMNHome_promoteSecondary:test_promoteSecondary_OnlyOwner_reverts() (gas: 10919)
RMNHome_promoteSecondary:test_promoteSecondary_success() (gas: 42700)
RMNHome_promoteSecondaryAndRevokePrimary:test_promoteSecondaryAndRevokePrimary_OnlyOwner_reverts() (gas: 10935)
RMNHome_promoteSecondaryAndRevokePrimary:test_promoteSecondaryAndRevokePrimary_success() (gas: 209)
RMNHome_revokeSecondary:test_revokeSecondary_ConfigDigestMismatch_reverts() (gas: 18865)
RMNHome_revokeSecondary:test_revokeSecondary_OnlyOwner_reverts() (gas: 10943)
RMNHome_revokeSecondary:test_revokeSecondary_success() (gas: 27886)
RMNHome_setDynamicConfig:test_setDynamicConfig_DigestNotFound_reverts() (gas: 30074)
RMNHome_setDynamicConfig:test_setDynamicConfig_MinObserversTooHigh_reverts() (gas: 18798)
RMNHome_setDynamicConfig:test_setDynamicConfig_OnlyOwner_reverts() (gas: 14093)
RMNHome_setDynamicConfig:test_setDynamicConfig_success() (gas: 108289)
RMNHome_setSecondary:test_setSecondary_DuplicateOffchainPublicKey_reverts() (gas: 16743)
RMNHome_setSecondary:test_setSecondary_DuplicatePeerId_reverts() (gas: 16185)
RMNHome_setSecondary:test_setSecondary_DuplicateSourceChain_reverts() (gas: 22544)
RMNHome_setSecondary:test_setSecondary_MinObserversTooHigh_reverts() (gas: 22983)
RMNHome_setSecondary:test_setSecondary_OnlyOwner_reverts() (gas: 15167)
RMNHome_setSecondary:test_setSecondary_OutOfBoundsNodesLength_reverts() (gas: 73924)
RMNHome_setSecondary:test_setSecondary_OutOfBoundsObserverNodeIndex_reverts() (gas: 22688)
RMNHome_setSecondary:test_setSecondary_success() (gas: 594559)
RMNRemote_constructor:test_constructor_success() (gas: 8334)
RMNRemote_constructor:test_constructor_zeroChainSelector_reverts() (gas: 59165)
RMNRemote_curse:test_curse_AlreadyCursed_duplicateSubject_reverts() (gas: 154457)
Expand Down
20 changes: 14 additions & 6 deletions contracts/src/v0.8/ccip/rmn/RMNHome.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ contract RMNHome is OwnerIsCreator, ITypeAndVersion {
event ConfigSet(bytes32 configDigest, VersionedConfig versionedConfig);
event ConfigRevoked(bytes32 configDigest);
event DynamicConfigSet(bytes32 indexed configDigest, DynamicConfig dynamicConfig);
event ConfigPromoted(bytes32 configDigest);

struct Node {
bytes32 peerId; // Used for p2p communication.
Expand Down Expand Up @@ -147,7 +148,10 @@ contract RMNHome is OwnerIsCreator, ITypeAndVersion {
/// @param newConfig The new config to set.
/// @param digestToOverwrite The digest of the config to overwrite, or ZERO_DIGEST if no config is to be overwritten.
/// This is done to prevent accidental overwrites.
function setSecondary(Config calldata newConfig, bytes32 digestToOverwrite) external onlyOwner {
function setSecondary(
Config calldata newConfig,
bytes32 digestToOverwrite
) external onlyOwner returns (bytes32 newConfigDigest) {
_validateStaticConfig(newConfig.staticConfig);
_validateDynamicConfig(newConfig.dynamicConfig, newConfig.staticConfig.nodes.length);

Expand All @@ -163,29 +167,31 @@ contract RMNHome is OwnerIsCreator, ITypeAndVersion {
}

uint32 newVersion = ++s_configCount;
bytes32 newConfigDigest = _getConfigDigest(newConfig.staticConfig, newVersion);
newConfigDigest = _getConfigDigest(newConfig.staticConfig, newVersion);
s_configs[secondaryConfigIndex] = newConfig;
s_configVersions[secondaryConfigIndex] = newVersion;
s_configDigests[secondaryConfigIndex] = newConfigDigest;

emit ConfigSet(newConfigDigest, VersionedConfig({version: newVersion, config: newConfig}));

return newConfigDigest;
}

function setDynamicConfig(DynamicConfig calldata newDynamicConfig, bytes32 digestToOverwrite) external onlyOwner {
function setDynamicConfig(DynamicConfig calldata newDynamicConfig, bytes32 currentDigest) external onlyOwner {
for (uint256 i = 0; i < MAX_CONCURRENT_CONFIGS; ++i) {
if (s_configDigests[i] == digestToOverwrite) {
if (s_configDigests[i] == currentDigest && currentDigest != ZERO_DIGEST) {
Config memory currentConfig = s_configs[i];
_validateDynamicConfig(newDynamicConfig, currentConfig.staticConfig.nodes.length);

// Since the dynamic config doesn't change we don't have to update the digest or version.
s_configs[i].dynamicConfig = newDynamicConfig;

emit DynamicConfigSet(digestToOverwrite, newDynamicConfig);
emit DynamicConfigSet(currentDigest, newDynamicConfig);
return;
}
}

revert DigestNotFound(digestToOverwrite);
revert DigestNotFound(currentDigest);
}

/// @notice Revokes a specific config by digest.
Expand All @@ -212,6 +218,8 @@ contract RMNHome is OwnerIsCreator, ITypeAndVersion {
}

s_primaryConfigIndex ^= 1;

emit ConfigPromoted(digestToPromote);
}

/// @notice Promotes the secondary config to the primary config and revokes the primary config.
Expand Down
144 changes: 143 additions & 1 deletion contracts/src/v0.8/ccip/test/rmn/RMNHomeTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,109 @@ contract RMNHome_setSecondary is RMNHomeTest {
}
}

contract RMNHome_setDynamicConfig is RMNHomeTest {
function setUp() public override {
super.setUp();
s_rmnHome.setSecondary(_getBaseConfig(), ZERO_DIGEST);
}

function test_setDynamicConfig_success() public {
(bytes32 priorPrimaryDigest,) = s_rmnHome.getConfigDigests();

RMNHome.Config memory config = _getBaseConfig();
config.dynamicConfig.sourceChains[0].minObservers--;

(, bytes32 secondaryConfigDigest) = s_rmnHome.getConfigDigests();

vm.expectEmit();
emit RMNHome.DynamicConfigSet(secondaryConfigDigest, config.dynamicConfig);

s_rmnHome.setDynamicConfig(config.dynamicConfig, secondaryConfigDigest);

(RMNHome.VersionedConfig memory storedVersionedConfig, bool ok) = s_rmnHome.getConfig(secondaryConfigDigest);
assertTrue(ok);
assertEq(
storedVersionedConfig.config.dynamicConfig.sourceChains[0].minObservers,
config.dynamicConfig.sourceChains[0].minObservers
);

// Asser the digests don't change when updating the dynamic config
(bytes32 primaryDigest, bytes32 secondaryDigest) = s_rmnHome.getConfigDigests();
assertEq(primaryDigest, priorPrimaryDigest);
assertEq(secondaryDigest, secondaryConfigDigest);
}

// Asserts the validation function is being called
function test_setDynamicConfig_MinObserversTooHigh_reverts() public {
RMNHome.Config memory config = _getBaseConfig();
config.dynamicConfig.sourceChains[0].minObservers++;

vm.expectRevert(abi.encodeWithSelector(RMNHome.DigestNotFound.selector, ZERO_DIGEST));
s_rmnHome.setDynamicConfig(config.dynamicConfig, ZERO_DIGEST);
}

function test_setDynamicConfig_DigestNotFound_reverts() public {
// Zero always reverts
vm.expectRevert(abi.encodeWithSelector(RMNHome.DigestNotFound.selector, ZERO_DIGEST));
s_rmnHome.setDynamicConfig(_getBaseConfig().dynamicConfig, ZERO_DIGEST);

// Non-existent digest reverts
bytes32 nonExistentDigest = keccak256("nonExistentDigest");
vm.expectRevert(abi.encodeWithSelector(RMNHome.DigestNotFound.selector, nonExistentDigest));
s_rmnHome.setDynamicConfig(_getBaseConfig().dynamicConfig, nonExistentDigest);
}

function test_setDynamicConfig_OnlyOwner_reverts() public {
RMNHome.Config memory config = _getBaseConfig();

vm.startPrank(address(0));

vm.expectRevert("Only callable by owner");
s_rmnHome.setDynamicConfig(config.dynamicConfig, keccak256("configDigest"));
}
}

contract RMNHome_revokeSecondary is RMNHomeTest {
function test_revokeSecondary_success() public {}
// Sets two configs
function setUp() public override {
super.setUp();
bytes32 digest = s_rmnHome.setSecondary(_getBaseConfig(), ZERO_DIGEST);
s_rmnHome.promoteSecondary(digest);

RMNHome.Config memory config = _getBaseConfig();
config.dynamicConfig.sourceChains[0].minObservers--;
s_rmnHome.setSecondary(_getBaseConfig(), ZERO_DIGEST);
}

function test_revokeSecondary_success() public {
(bytes32 priorPrimaryDigest, bytes32 priorSecondaryDigest) = s_rmnHome.getConfigDigests();

vm.expectEmit();
emit RMNHome.ConfigRevoked(priorSecondaryDigest);

s_rmnHome.revokeSecondary(priorSecondaryDigest);

(RMNHome.VersionedConfig memory storedVersionedConfig, bool ok) = s_rmnHome.getConfig(priorSecondaryDigest);
assertFalse(ok);
// Ensure no old data is returned, even though it's still in storage
assertEq(storedVersionedConfig.version, 0);
assertEq(storedVersionedConfig.config.staticConfig.nodes.length, 0);
assertEq(storedVersionedConfig.config.dynamicConfig.sourceChains.length, 0);

// Asser the primary digest is unaffected but the secondary digest is set to zero
(bytes32 primaryDigest, bytes32 secondaryDigest) = s_rmnHome.getConfigDigests();
assertEq(primaryDigest, priorPrimaryDigest);
assertTrue(secondaryDigest != priorSecondaryDigest);
assertEq(secondaryDigest, ZERO_DIGEST);
}

function test_revokeSecondary_ConfigDigestMismatch_reverts() public {
(, bytes32 priorSecondaryDigest) = s_rmnHome.getConfigDigests();

bytes32 wrongDigest = keccak256("wrong_digest");
vm.expectRevert(abi.encodeWithSelector(RMNHome.ConfigDigestMismatch.selector, priorSecondaryDigest, wrongDigest));
s_rmnHome.revokeSecondary(wrongDigest);
}

function test_revokeSecondary_OnlyOwner_reverts() public {
vm.startPrank(address(0));
Expand All @@ -152,3 +253,44 @@ contract RMNHome_revokeSecondary is RMNHomeTest {
s_rmnHome.revokeSecondary(keccak256("configDigest"));
}
}

contract RMNHome_promoteSecondary is RMNHomeTest {
function test_promoteSecondary_success() public {
(bytes32 priorPrimaryDigest, bytes32 priorSecondaryDigest) = s_rmnHome.getConfigDigests();

vm.expectEmit();
emit RMNHome.ConfigPromoted(priorSecondaryDigest);

s_rmnHome.promoteSecondary(priorSecondaryDigest);

(bytes32 primaryDigest, bytes32 secondaryDigest) = s_rmnHome.getConfigDigests();
assertEq(primaryDigest, priorSecondaryDigest);
assertEq(secondaryDigest, priorPrimaryDigest);
}

function test_promoteSecondary_ConfigDigestMismatch_reverts() public {
(, bytes32 priorSecondaryDigest) = s_rmnHome.getConfigDigests();

bytes32 wrongDigest = keccak256("wrong_digest");
vm.expectRevert(abi.encodeWithSelector(RMNHome.ConfigDigestMismatch.selector, priorSecondaryDigest, wrongDigest));
s_rmnHome.promoteSecondary(wrongDigest);
}

function test_promoteSecondary_OnlyOwner_reverts() public {
vm.startPrank(address(0));

vm.expectRevert("Only callable by owner");
s_rmnHome.promoteSecondary(keccak256("configDigest"));
}
}

contract RMNHome_promoteSecondaryAndRevokePrimary is RMNHomeTest {
function test_promoteSecondaryAndRevokePrimary_success() public {}

function test_promoteSecondaryAndRevokePrimary_OnlyOwner_reverts() public {
vm.startPrank(address(0));

vm.expectRevert("Only callable by owner");
s_rmnHome.promoteSecondaryAndRevokePrimary(keccak256("toPromote"), keccak256("ToRevoke"));
}
}

0 comments on commit 36720d2

Please sign in to comment.