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

add legacy fallback to RMNRemote #15422

Merged
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
10 changes: 10 additions & 0 deletions contracts/.changeset/bright-jokes-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@chainlink/contracts': patch
---

add legacy fallback to RMN


PR issue: CCIP-4261

Solidity Review issue: CCIP-3966
32 changes: 16 additions & 16 deletions contracts/gas-snapshots/ccip.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -573,27 +573,27 @@ RMNHome_validateStaticAndDynamicConfig:test_validateStaticAndDynamicConfig_Dupli
RMNHome_validateStaticAndDynamicConfig:test_validateStaticAndDynamicConfig_NotEnoughObservers_reverts() (gas: 21405)
RMNHome_validateStaticAndDynamicConfig:test_validateStaticAndDynamicConfig_OutOfBoundsNodesLength_reverts() (gas: 137318)
RMNHome_validateStaticAndDynamicConfig:test_validateStaticAndDynamicConfig_OutOfBoundsObserverNodeIndex_reverts() (gas: 20522)
RMNRemote_constructor:test_constructor_success() (gas: 8334)
RMNRemote_constructor:test_constructor_zeroChainSelector_reverts() (gas: 59184)
RMNRemote_curse:test_curse_AlreadyCursed_duplicateSubject_reverts() (gas: 154479)
RMNRemote_curse:test_curse_calledByNonOwner_reverts() (gas: 18712)
RMNRemote_curse:test_curse_success() (gas: 149431)
RMNRemote_global_and_legacy_curses:test_global_and_legacy_curses_success() (gas: 133512)
RMNRemote_constructor:test_constructor() (gas: 8398)
RMNRemote_curse:test_curse_AlreadyCursed_duplicateSubject_reverts() (gas: 154501)
RMNRemote_curse:test_curse_calledByNonOwner_reverts() (gas: 18734)
RMNRemote_curse:test_curse_success() (gas: 149475)
RMNRemote_global_and_legacy_curses:test_global_and_legacy_curses_success() (gas: 133441)
RMNRemote_isBlessed:test_isBlessed() (gas: 17588)
RMNRemote_setConfig:test_setConfig_ZeroValueNotAllowed_revert() (gas: 37971)
RMNRemote_setConfig:test_setConfig_addSigner_removeSigner_success() (gas: 993448)
RMNRemote_setConfig:test_setConfig_duplicateOnChainPublicKey_reverts() (gas: 323540)
RMNRemote_setConfig:test_setConfig_invalidSignerOrder_reverts() (gas: 80201)
RMNRemote_setConfig:test_setConfig_notEnoughSigners_reverts() (gas: 54232)
RMNRemote_uncurse:test_uncurse_NotCursed_duplicatedUncurseSubject_reverts() (gas: 51993)
RMNRemote_uncurse:test_uncurse_calledByNonOwner_reverts() (gas: 18682)
RMNRemote_uncurse:test_uncurse_success() (gas: 40171)
RMNRemote_verify_withConfigNotSet:test_verify_reverts() (gas: 13578)
RMNRemote_verify_withConfigSet:test_verify_InvalidSignature_reverts() (gas: 96449)
RMNRemote_verify_withConfigSet:test_verify_OutOfOrderSignatures_duplicateSignature_reverts() (gas: 94267)
RMNRemote_verify_withConfigSet:test_verify_OutOfOrderSignatures_not_sorted_reverts() (gas: 101330)
RMNRemote_verify_withConfigSet:test_verify_ThresholdNotMet_reverts() (gas: 304634)
RMNRemote_verify_withConfigSet:test_verify_UnexpectedSigner_reverts() (gas: 428126)
RMNRemote_verify_withConfigSet:test_verify_success() (gas: 86159)
RMNRemote_uncurse:test_uncurse_NotCursed_duplicatedUncurseSubject_reverts() (gas: 51940)
RMNRemote_uncurse:test_uncurse_calledByNonOwner_reverts() (gas: 18615)
RMNRemote_uncurse:test_uncurse_success() (gas: 40135)
RMNRemote_verify_withConfigNotSet:test_verify_reverts() (gas: 13600)
RMNRemote_verify_withConfigSet:test_verify_InvalidSignature_reverts() (gas: 96471)
RMNRemote_verify_withConfigSet:test_verify_OutOfOrderSignatures_duplicateSignature_reverts() (gas: 94289)
RMNRemote_verify_withConfigSet:test_verify_OutOfOrderSignatures_not_sorted_reverts() (gas: 101352)
RMNRemote_verify_withConfigSet:test_verify_ThresholdNotMet_reverts() (gas: 304744)
RMNRemote_verify_withConfigSet:test_verify_UnexpectedSigner_reverts() (gas: 428284)
RMNRemote_verify_withConfigSet:test_verify_success() (gas: 86181)
RateLimiter_constructor:test_Constructor_Success() (gas: 19806)
RateLimiter_consume:test_AggregateValueMaxCapacityExceeded_Revert() (gas: 16042)
RateLimiter_consume:test_AggregateValueRateLimitReached_Revert() (gas: 22435)
Expand Down
34 changes: 28 additions & 6 deletions contracts/src/v0.8/ccip/rmn/RMNRemote.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
pragma solidity 0.8.24;

import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {IRMN} from "../interfaces/IRMN.sol";
import {IRMNRemote} from "../interfaces/IRMNRemote.sol";

import {Ownable2StepMsgSender} from "../../shared/access/Ownable2StepMsgSender.sol";
Expand All @@ -19,7 +20,10 @@ bytes16 constant LEGACY_CURSE_SUBJECT = 0x01000000000000000000000000000000;
bytes16 constant GLOBAL_CURSE_SUBJECT = 0x01000000000000000000000000000001;

/// @notice This contract supports verification of RMN reports for any Any2EVM OffRamp.
contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote {
/// @dev This contract implements both the new IRMNRemote interface and the legacy IRMN interface. This is to allow for
/// a seamless migration from the legacy RMN contract to this one. The only function that has been dropped in the newer
/// interface is `isBlessed`. For the `isBlessed` function, this contract relays the call to the legacy RMN contract.
contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote, IRMN {
using EnumerableSet for EnumerableSet.Bytes16Set;

error AlreadyCursed(bytes16 subject);
Expand All @@ -33,6 +37,7 @@ contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote {
error ThresholdNotMet();
error UnexpectedSigner();
error ZeroValueNotAllowed();
error IsBlessedNotAvailable();

event ConfigSet(uint32 indexed version, Config config);
event Cursed(bytes16[] subjects);
Expand Down Expand Up @@ -67,6 +72,7 @@ contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote {

string public constant override typeAndVersion = "RMNRemote 1.6.0-dev";
uint64 internal immutable i_localChainSelector;
IRMN internal immutable i_legacyRMN;

Config private s_config;
uint32 private s_configCount;
Expand All @@ -80,11 +86,11 @@ contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote {
mapping(address signer => bool exists) private s_signers; // for more gas efficient verify.

/// @param localChainSelector the chain selector of the chain this contract is deployed to.
constructor(
uint64 localChainSelector
) {
constructor(uint64 localChainSelector, IRMN legacyRMN) {
if (localChainSelector == 0) revert ZeroValueNotAllowed();
i_localChainSelector = localChainSelector;

i_legacyRMN = legacyRMN;
}

// ================================================================
Expand Down Expand Up @@ -248,7 +254,7 @@ contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote {
}

/// @inheritdoc IRMNRemote
function isCursed() external view returns (bool) {
function isCursed() external view override(IRMN, IRMNRemote) returns (bool) {
// There are zero curses under normal circumstances, which means it's cheaper to check for the absence of curses.
// than to check the subject list twice, as we have to check for both the legacy and global curse subjects.
if (s_cursedSubjects.length() == 0) {
Expand All @@ -260,12 +266,28 @@ contract RMNRemote is Ownable2StepMsgSender, ITypeAndVersion, IRMNRemote {
/// @inheritdoc IRMNRemote
function isCursed(
bytes16 subject
) external view returns (bool) {
) external view override(IRMN, IRMNRemote) returns (bool) {
// There are zero curses under normal circumstances, which means it's cheaper to check for the absence of curses.
// than to check the subject list twice, as we have to check for both the given and global curse subjects.
if (s_cursedSubjects.length() == 0) {
return false;
}
return s_cursedSubjects.contains(subject) || s_cursedSubjects.contains(GLOBAL_CURSE_SUBJECT);
}

// ================================================================
// │ Legacy pass through │
// ================================================================

/// @inheritdoc IRMN
/// @dev This function is only expected to be used for messages from CCIP versions below 1.6.
function isBlessed(
TaggedRoot calldata taggedRoot
) external view returns (bool) {
if (i_legacyRMN == IRMN(address(0))) {
revert IsBlessedNotAvailable();
}

return i_legacyRMN.isBlessed(taggedRoot);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.24;

import {RMNRemote} from "../../../rmn/RMNRemote.sol";
import {RMNRemoteSetup} from "./RMNRemoteSetup.t.sol";

contract RMNRemote_constructor is RMNRemoteSetup {
function test_constructor_success() public view {
function test_constructor() public view {
assertEq(s_rmnRemote.getLocalChainSelector(), 1);
}

function test_constructor_zeroChainSelector_reverts() public {
vm.expectRevert(RMNRemote.ZeroValueNotAllowed.selector);
new RMNRemote(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.24;

import {IRMN} from "../../../interfaces/IRMN.sol";

import {RMNRemote} from "../../../rmn/RMNRemote.sol";
import {RMNRemoteSetup} from "./RMNRemoteSetup.t.sol";

contract RMNRemote_isBlessed is RMNRemoteSetup {
function test_isBlessed() public {
IRMN.TaggedRoot memory taggedRoot = IRMN.TaggedRoot({root: keccak256("root"), commitStore: makeAddr("commitStore")});

vm.mockCall(
address(s_legacyRMN), abi.encodeWithSelector(s_legacyRMN.isBlessed.selector, taggedRoot), abi.encode(true)
);

assertTrue(s_rmnRemote.isBlessed(taggedRoot));

vm.mockCall(
address(s_legacyRMN), abi.encodeWithSelector(s_legacyRMN.isBlessed.selector, taggedRoot), abi.encode(false)
);

assertFalse(s_rmnRemote.isBlessed(taggedRoot));
}

function test_isBlessed_RevertWhen_IsBlessedNotAvailable() public {
IRMN.TaggedRoot memory taggedRoot = IRMN.TaggedRoot({root: keccak256("root"), commitStore: makeAddr("commitStore")});

s_rmnRemote = new RMNRemote(100, IRMN(address(0)));

vm.expectRevert(RMNRemote.IsBlessedNotAvailable.selector);
s_rmnRemote.isBlessed(taggedRoot);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.24;

import {IRMN} from "../../../interfaces/IRMN.sol";
import {IRMNRemote} from "../../../interfaces/IRMNRemote.sol";

import {Internal} from "../../../libraries/Internal.sol";
import {RMNRemote} from "../../../rmn/RMNRemote.sol";
import {BaseTest} from "../../BaseTest.t.sol";
Expand All @@ -21,9 +23,11 @@ contract RMNRemoteSetup is BaseTest {
bytes16 internal constant CURSE_SUBJ_2 = bytes16(keccak256("subject 2"));
bytes16[] internal s_curseSubjects;

IRMN internal s_legacyRMN = IRMN(makeAddr("legacyRMN"));

function setUp() public virtual override {
super.setUp();
s_rmnRemote = new RMNRemote(1);
s_rmnRemote = new RMNRemote(1, s_legacyRMN);
OFF_RAMP_ADDRESS = makeAddr("OFF RAMP");
s_curseSubjects = [CURSE_SUBJ_1, CURSE_SUBJ_2];

Expand Down
37 changes: 33 additions & 4 deletions core/gethwrappers/ccip/generated/rmn_remote/rmn_remote.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ registry_module_owner_custom: ../../../contracts/solc/v0.8.24/RegistryModuleOwne
report_codec: ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.abi ../../../contracts/solc/v0.8.24/ReportCodec/ReportCodec.bin 6c943b39f003aa67c3cefa19a8ff99e846236a058e1ceae77569c3a065ffd5c7
rmn_home: ../../../contracts/solc/v0.8.24/RMNHome/RMNHome.abi ../../../contracts/solc/v0.8.24/RMNHome/RMNHome.bin 84ca84b3d0c00949905a3d10a91255f877cf32b2a0d7f7f7ce3121ced34a8cb7
rmn_proxy_contract: ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.abi ../../../contracts/solc/v0.8.24/ARMProxy/ARMProxy.bin b048d8e752e3c41113ebb305c1efa06737ad36b4907b93e627fb0a3113023454
rmn_remote: ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.abi ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.bin faee0b0cdbe67f2e28deccf12acd4df13dd90992f6cbc0ba17bab845b8f4eb1c
rmn_remote: ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.abi ../../../contracts/solc/v0.8.24/RMNRemote/RMNRemote.bin 941118dfdc6bb042c339cfe8d8e0c7a0b486afb731a785d58a64994e7a13c459
router: ../../../contracts/solc/v0.8.24/Router/Router.abi ../../../contracts/solc/v0.8.24/Router/Router.bin 2e4f0a7826c8abb49d882bb49fc5ff20a186dbd3137624b9097ffed903ae4888
token_admin_registry: ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.abi ../../../contracts/solc/v0.8.24/TokenAdminRegistry/TokenAdminRegistry.bin 397bc7be08c2848c0f4715f90b16206d6367f78ffb7cd48e2b1dfc0ccc5aea26
token_pool: ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.abi ../../../contracts/solc/v0.8.24/TokenPool/TokenPool.bin da86a1407f31134e7246bde63c80ce8c78ce7d7b44e267f3c1f6030441ff4252
Expand Down
5 changes: 4 additions & 1 deletion deployment/ccip/changeset/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import (
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"
Copy link
Contributor

Choose a reason for hiding this comment

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

🔥

"golang.org/x/sync/errgroup"

cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3"

"github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal"

"github.com/smartcontractkit/chainlink/deployment"
Expand Down Expand Up @@ -599,6 +600,8 @@ func deployChainContracts(
chain.DeployerKey,
chain.Client,
chain.Selector,
// Indicates no legacy RMN contract
common.HexToAddress("0x0"),
)
return deployment.ContractDeploy[*rmn_remote.RMNRemote]{
rmnRemoteAddr, rmnRemote, tx, deployment.NewTypeAndVersion(RMNRemote, deployment.Version1_6_0_dev), err2,
Expand Down
Loading