Skip to content

Commit

Permalink
Merge branch 'ccip-develop' into feat/CCIP-384-remove-signature
Browse files Browse the repository at this point in the history
  • Loading branch information
agusaldasoro authored Jun 27, 2024
2 parents b77f2cf + 62c1bab commit 6201d24
Show file tree
Hide file tree
Showing 94 changed files with 6,744 additions and 3,499 deletions.
9 changes: 3 additions & 6 deletions .github/actions/notify-slack-jobs-result/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ inputs:
slack_thread_ts:
description: "The Slack thread timestamp to post the message to, handy for keeping multiple related results in a single thread"
required: false
base64_parsed_results:
description: "Base64 encoded parsed results to use"
required: false

runs:
using: composite
Expand Down Expand Up @@ -67,9 +64,9 @@ runs:
break
done
echo "Success: $ALL_SUCCESS"
echo all_success=$ALL_SUCCESS >> $GITHUB_OUTPUT

FORMATTED_RESULTS=$(echo $PARSED_RESULTS | jq -s '[.[]
| {
conclusion: .conclusion,
Expand All @@ -83,7 +80,7 @@ runs:
echo "Nothing to post, no results found"
exit 0
fi

echo "Formatted Results:"
echo $FORMATTED_RESULTS
Expand Down
678 changes: 526 additions & 152 deletions .github/workflows/ccip-client-compatibility-tests.yml

Large diffs are not rendered by default.

10 changes: 3 additions & 7 deletions .github/workflows/ccip-load-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ jobs:
SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }}

post-test-results-to-slack:
name: Post Test Results for ${{ matrix.network }}
name: Post Test Results
if: ${{ failure() && needs.start-slack-thread.result != 'skipped' && needs.start-slack-thread.result != 'cancelled' }}
environment: integration
permissions:
Expand All @@ -268,10 +268,6 @@ jobs:
contents: read
runs-on: ubuntu-latest
needs: start-slack-thread
strategy:
fail-fast: false
matrix:
network: [CCIP]
steps:
- name: Checkout the repo
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
Expand All @@ -283,8 +279,8 @@ jobs:
github_token: ${{ github.token }}
github_repository: ${{ github.repository }}
workflow_run_id: ${{ github.run_id }}
github_job_name_regex: ^${{ matrix.network }} (.*?)$
message_title: ${{ matrix.network }}
github_job_name_regex: ^CCIP (.*)$
message_title: CCIP Jobs
slack_channel_id: "#ccip-testing"
slack_bot_token: ${{ secrets.QA_SLACK_API_KEY }}
slack_thread_ts: ${{ needs.start-slack-thread.outputs.thread_ts }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -633,9 +633,9 @@ jobs:
path: ./integration-tests/smoke/traces/trace-data.json
- name: Print failed test summary
if: always()
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@fc3e0df622521019f50d772726d6bf8dc919dd38 # v2.3.19
uses: smartcontractkit/chainlink-github-actions/chainlink-testing-framework/show-test-summary@1587f59bfd626b668d303abbc90fee41b12397e6 # v2.3.23
with:
test_directory: ./integration-tests/smoke/
test_directories: ./integration-tests/smoke/,./integration-tests/ccip-tests/smoke/

### Used to check the required checks box when the matrix completes
eth-smoke-tests:
Expand Down
796 changes: 409 additions & 387 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions contracts/scripts/native_solc_compile_all_ccip
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,14 @@ compileContract ccip/RMN.sol
compileContract ccip/ARMProxy.sol
compileContract ccip/tokenAdminRegistry/TokenAdminRegistry.sol
compileContract ccip/tokenAdminRegistry/RegistryModuleOwnerCustom.sol
compileContract ccip/capability/CCIPCapabilityConfiguration.sol
compileContract ccip/capability/CCIPConfig.sol

# Test helpers
compileContract ccip/test/helpers/BurnMintERC677Helper.sol
compileContract ccip/test/helpers/CommitStoreHelper.sol
compileContract ccip/test/helpers/MessageHasher.sol
compileContract ccip/test/helpers/receivers/MaybeRevertMessageReceiver.sol
compileContract ccip/test/mocks/MockRMN.sol
compileContract ccip/test/mocks/MockRMN1_0.sol
compileContract ccip/test/mocks/MockE2EUSDCTokenMessenger.sol
compileContract ccip/test/mocks/MockE2EUSDCTransmitter.sol
compileContract ccip/test/WETH9.sol
Expand Down
829 changes: 594 additions & 235 deletions contracts/src/v0.8/ccip/RMN.sol

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ pragma solidity 0.8.24;

import {ICapabilityConfiguration} from "../../keystone/interfaces/ICapabilityConfiguration.sol";
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {ICapabilityRegistry} from "./interfaces/ICapabilityRegistry.sol";
import {ICapabilitiesRegistry} from "./interfaces/ICapabilitiesRegistry.sol";

import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";

import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/interfaces/IERC165.sol";
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";

/// @notice CCIPCapabilityConfiguration stores the configuration for the CCIP capability.
/// We have two classes of configuration: chain configuration and DON (in the CapabilityRegistry sense) configuration.
/// @notice CCIPConfig stores the configuration for the CCIP capability.
/// We have two classes of configuration: chain configuration and DON (in the CapabilitiesRegistry sense) configuration.
/// Each chain will have a single configuration which includes information like the router address.
/// Each CR DON will have up to four configurations: for each of (commit, exec), one blue and one green configuration.
/// This is done in order to achieve "blue-green" deployments.
contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator {
contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator, IERC165 {
using EnumerableSet for EnumerableSet.UintSet;

/// @notice Emitted when a chain's configuration is set.
Expand All @@ -28,7 +29,7 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio

error ChainConfigNotSetForChain(uint64 chainSelector);
error NodeNotInRegistry(bytes32 p2pId);
error OnlyCapabilityRegistryCanCall();
error OnlyCapabilitiesRegistryCanCall();
error ChainSelectorNotFound(uint64 chainSelector);
error ChainSelectorNotSet();
error TooManyOCR3Configs();
Expand Down Expand Up @@ -72,7 +73,7 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio
/// @notice Chain configuration.
/// Changes to chain configuration are detected out-of-band in plugins and decoded offchain.
struct ChainConfig {
bytes32[] readers; // The P2P IDs of the readers for the chain. These IDs must be registered in the capability registry.
bytes32[] readers; // The P2P IDs of the readers for the chain. These IDs must be registered in the capabilities registry.
uint8 fChain; // The fault tolerance parameter of the chain.
bytes config; // The chain configuration. This is kept intentionally opaque so as to add fields in the future if needed.
}
Expand Down Expand Up @@ -108,10 +109,10 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio
}

/// @notice Type and version override.
string public constant override typeAndVersion = "CCIPCapabilityConfiguration 1.6.0-dev";
string public constant override typeAndVersion = "CCIPConfig 1.6.0-dev";

/// @notice The canonical capability registry address.
address internal immutable i_capabilityRegistry;
/// @notice The canonical capabilities registry address.
address internal immutable i_capabilitiesRegistry;

/// @notice chain configuration for each chain that CCIP is deployed on.
mapping(uint64 chainSelector => ChainConfig chainConfig) internal s_chainConfigurations;
Expand All @@ -131,9 +132,14 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio
uint8 internal constant MAX_OCR3_CONFIGS_PER_DON = 4;
uint8 internal constant MAX_NUM_ORACLES = 31;

/// @param capabilityRegistry the canonical capability registry address.
constructor(address capabilityRegistry) {
i_capabilityRegistry = capabilityRegistry;
/// @param capabilitiesRegistry the canonical capabilities registry address.
constructor(address capabilitiesRegistry) {
i_capabilitiesRegistry = capabilitiesRegistry;
}

/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return interfaceId == type(ICapabilityConfiguration).interfaceId || interfaceId == type(IERC165).interfaceId;
}

// ================================================================
Expand Down Expand Up @@ -180,8 +186,8 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio
uint64, /* configCount */
uint32 donId
) external override {
if (msg.sender != i_capabilityRegistry) {
revert OnlyCapabilityRegistryCanCall();
if (msg.sender != i_capabilitiesRegistry) {
revert OnlyCapabilitiesRegistryCanCall();
}

OCR3Config[] memory ocr3Configs = abi.decode(config, (OCR3Config[]));
Expand Down Expand Up @@ -398,7 +404,7 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio
}
if (cfg.bootstrapP2PIds.length > cfg.p2pIds.length) revert TooManyBootstrapP2PIds();

// Check that the readers are in the capability registry.
// Check that the readers are in the capabilities registry.
// TODO: check for duplicate signers, duplicate p2p ids, etc.
// TODO: check that p2p ids in cfg.bootstrapP2PIds are included in cfg.p2pIds.
for (uint256 i = 0; i < cfg.signers.length; ++i) {
Expand Down Expand Up @@ -473,7 +479,7 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio
bytes32[] memory readers = chainConfig.readers;
uint64 chainSelector = chainConfigAdds[i].chainSelector;

// Verify that the provided readers are present in the capability registry.
// Verify that the provided readers are present in the capabilities registry.
for (uint256 j = 0; j < readers.length; j++) {
_ensureInRegistry(readers[j]);
}
Expand All @@ -490,10 +496,10 @@ contract CCIPCapabilityConfiguration is ITypeAndVersion, ICapabilityConfiguratio
}
}

/// @notice Helper function to ensure that a node is in the capability registry.
/// @notice Helper function to ensure that a node is in the capabilities registry.
/// @param p2pId The P2P ID of the node to check.
function _ensureInRegistry(bytes32 p2pId) internal view {
(ICapabilityRegistry.NodeInfo memory node,) = ICapabilityRegistry(i_capabilityRegistry).getNode(p2pId);
ICapabilitiesRegistry.NodeInfo memory node = ICapabilitiesRegistry(i_capabilitiesRegistry).getNode(p2pId);
if (node.p2pId == bytes32("")) {
revert NodeNotInRegistry(p2pId);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

interface ICapabilityRegistry {
interface ICapabilitiesRegistry {
struct NodeInfo {
/// @notice The id of the node operator that manages this node
uint32 nodeOperatorId;
/// @notice The number of times the node's configuration has been updated
uint32 configCount;
/// @notice The ID of the Workflow DON that the node belongs to. A node can
/// only belong to one DON that accepts Workflows.
uint32 workflowDONId;
/// @notice The signer address for application-layer message verification.
bytes32 signer;
/// @notice This is an Ed25519 public key that is used to identify a node.
/// This key is guaranteed to be unique in the CapabilityRegistry. It is
/// This key is guaranteed to be unique in the CapabilitiesRegistry. It is
/// used to identify a node in the the P2P network.
bytes32 p2pId;
/// @notice The list of hashed capability IDs supported by the node
bytes32[] hashedCapabilityIds;
/// @notice The list of capabilities DON Ids supported by the node. A node
/// can belong to multiple capabilities DONs. This list does not include a
/// Workflow DON id if the node belongs to one.
uint256[] capabilitiesDONIds;
}

/// @notice Gets a node's data
/// @param p2pId The P2P ID of the node to query for
/// @return NodeInfo The node data
/// @return configCount The number of times the node has been configured
function getNode(bytes32 p2pId) external view returns (NodeInfo memory, uint32 configCount);
function getNode(bytes32 p2pId) external view returns (NodeInfo memory);
}
4 changes: 2 additions & 2 deletions contracts/src/v0.8/ccip/interfaces/IRMN.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ interface IRMN {
/// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed.
function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool);

/// @notice Iff there is an active global curse, or an active legacy curse (for backwards compatibility), this function returns true.
/// @notice Iff there is an active global or legacy curse, this function returns true.
function isCursed() external view returns (bool);

/// @notice Iff there is an active global curse or an active subject curse, this function returns true.
/// @notice Iff there is an active global curse, or an active curse for `subject`, this function returns true.
/// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)).
function isCursed(bytes16 subject) external view returns (bool);
}
13 changes: 7 additions & 6 deletions contracts/src/v0.8/ccip/test/arm/ARMProxy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,36 @@ import {IRMN} from "../../interfaces/IRMN.sol";
import {ARMProxy} from "../../ARMProxy.sol";
import {RMN} from "../../RMN.sol";
import {MockRMN} from "../mocks/MockRMN.sol";
import {RMNSetup} from "./RMNSetup.t.sol";
import {RMNSetup, makeSubjects} from "./RMNSetup.t.sol";

contract ARMProxyTest is RMNSetup {
event ARMSet(address arm);

MockRMN internal s_mockRMN;
ARMProxy internal s_armProxy;

function setUp() public virtual override {
RMNSetup.setUp();
s_mockRMN = new MockRMN();
s_armProxy = new ARMProxy(address(s_rmn));
}

function test_ARMIsCursed_Success() public {
s_armProxy.setARM(address(s_mockRMN));
assertFalse(IRMN(address(s_armProxy)).isCursed());
RMN(address(s_armProxy)).voteToCurse(bytes32(0));
s_mockRMN.setGlobalCursed(true);
assertTrue(IRMN(address(s_armProxy)).isCursed());
}

function test_ARMIsBlessed_Success() public {
s_armProxy.setARM(address(s_mockRMN));
s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}), true);
assertTrue(IRMN(address(s_armProxy)).isBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)})));
RMN(address(s_armProxy)).voteToCurse(bytes32(0));
s_mockRMN.setTaggedRootBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)}), false);
assertFalse(IRMN(address(s_armProxy)).isBlessed(IRMN.TaggedRoot({commitStore: address(0), root: bytes32(0)})));
}

function test_ARMCallRevertReasonForwarded() public {
bytes memory err = bytes("revert");
s_mockRMN.setRevert(err);
s_mockRMN.setIsCursedRevert(err);
s_armProxy.setARM(address(s_mockRMN));
vm.expectRevert(abi.encodeWithSelector(MockRMN.CustomError.selector, err));
IRMN(address(s_armProxy)).isCursed();
Expand Down
10 changes: 4 additions & 6 deletions contracts/src/v0.8/ccip/test/arm/ARMProxy_standalone.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {ARMProxy} from "../../ARMProxy.sol";
import {Test} from "forge-std/Test.sol";

contract ARMProxyStandaloneTest is Test {
event ARMSet(address arm);

address internal constant EMPTY_ADDRESS = address(0x1);
address internal constant OWNER_ADDRESS = 0xC0ffeeEeC0fFeeeEc0ffeEeEc0ffEEEEC0FfEEee;
address internal constant MOCK_RMN_ADDRESS = 0x1337133713371337133713371337133713371337;
Expand All @@ -23,14 +21,14 @@ contract ARMProxyStandaloneTest is Test {

function test_Constructor() public {
vm.expectEmit();
emit ARMSet(MOCK_RMN_ADDRESS);
emit ARMProxy.ARMSet(MOCK_RMN_ADDRESS);
ARMProxy proxy = new ARMProxy(MOCK_RMN_ADDRESS);
assertEq(proxy.getARM(), MOCK_RMN_ADDRESS);
}

function test_SetARM() public {
vm.expectEmit();
emit ARMSet(MOCK_RMN_ADDRESS);
emit ARMProxy.ARMSet(MOCK_RMN_ADDRESS);
vm.prank(OWNER_ADDRESS);
s_armProxy.setARM(MOCK_RMN_ADDRESS);
assertEq(s_armProxy.getARM(), MOCK_RMN_ADDRESS);
Expand All @@ -57,9 +55,9 @@ contract ARMProxyStandaloneTest is Test {
);
if (expectedSuccess) {
vm.mockCall(MOCK_ARM_ADDRESS, 0, call, ret);
vm.mockCall(MOCK_RMN_ADDRESS, 0, call, ret);
} else {
vm.mockCallRevert(MOCK_ARM_ADDRESS, 0, call, ret);
vm.mockCallRevert(MOCK_RMN_ADDRESS, 0, call, ret);
}
(bool actualSuccess, bytes memory result) = address(s_armProxy).call(call);
vm.clearMockedCalls();
Expand Down
Loading

0 comments on commit 6201d24

Please sign in to comment.