Skip to content

Commit

Permalink
Merge branch 'ccip-develop' into overflow-exec-plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
0xnogo authored Jul 11, 2024
2 parents e32acaa + 2bb582b commit 67bc739
Show file tree
Hide file tree
Showing 40 changed files with 753 additions and 271 deletions.
5 changes: 5 additions & 0 deletions .changeset/gentle-zebras-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ccip": patch
---

Bumped chain selectors
4 changes: 4 additions & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ flake.lock @smartcontractkit/prodsec-public
# CCIP override
/core/ @smartcontractkit/ccip
/contracts/ @smartcontractkit/ccip-onchain @makramkd @elatoskinas @RayXpub
go.mod @smartcontractkit/ccip @smartcontractkit/prodsec-public @smartcontractkit/releng @smartcontractkit/foundations
go.sum @smartcontractkit/ccip @smartcontractkit/prodsec-public @smartcontractkit/releng @smartcontractkit/foundations
integration-tests/go.mod @smartcontractkit/ccip @smartcontractkit/prodsec-public
integration-tests/go.sum @smartcontractkit/ccip @smartcontractkit/prodsec-public

# leave snapshots & changeset as ownerless
/contracts/gas-snapshots/
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ccip-client-compatibility-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,17 +167,17 @@ jobs:
echo "Will test all EVM implementations"
echo "evm_implementations=geth,besu,nethermind,erigon" >> $GITHUB_OUTPUT
fi
- name: Select Chainlink version
- name: Select Chainlink CCIP version
id: select-chainlink-version
run: |
PATH=$PATH:$(go env GOPATH)/bin
export PATH
if [ "$GITHUB_EVENT_NAME" = "schedule" ]; then
echo "Fetching latest Chainlink stable version"
echo "Fetching latest Chainlink CCIP stable version"
implementations_arr=()
# we use 100 days since we really want the latest one, and it's highly improbable there won't be a release in last 100 days
chainlink_version=$(ghlatestreleasechecker "smartcontractkit/chainlink" 100)
chainlink_version=$(ghlatestreleasechecker "smartcontractkit/ccip" 100)
echo "chainlink_version=$chainlink_version" >> $GITHUB_OUTPUT
elif [ "$GITHUB_EVENT_NAME" = "workflow_dispatch" ]; then
echo "Fetching Chainlink version from input"
Expand Down
5 changes: 5 additions & 0 deletions contracts/.changeset/neat-brooms-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/contracts': minor
---

We have multiple validation use-cases on-chain which requires the inputs to be a set, sorted-set or we need to do subset checks.Adding a library for these validations
192 changes: 98 additions & 94 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

15 changes: 14 additions & 1 deletion contracts/gas-snapshots/shared.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,17 @@ OpStackBurnMintERC677_constructor:testConstructorSuccess() (gas: 1743649)
OpStackBurnMintERC677_interfaceCompatibility:testBurnCompatibility() (gas: 298649)
OpStackBurnMintERC677_interfaceCompatibility:testMintCompatibility() (gas: 137957)
OpStackBurnMintERC677_interfaceCompatibility:testStaticFunctionsCompatibility() (gas: 13781)
OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12752)
OpStackBurnMintERC677_supportsInterface:testConstructorSuccess() (gas: 12752)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySubset_Reverts() (gas: 5460)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_EmptySuperset_Reverts() (gas: 4661)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_HasDuplicates_Reverts() (gas: 8265)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_NotASubset_Reverts() (gas: 12487)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubset() (gas: 4489)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_Equal() (gas: 1464)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SingleElementSubsetAndSuperset_NotEqual_Reverts() (gas: 6172)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetEqualsSuperset_NoRevert() (gas: 8867)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SubsetLargerThanSuperset_Reverts() (gas: 16544)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_SupersetHasDuplicates_Reverts() (gas: 9420)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSubset_Reverts() (gas: 7380)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_UnsortedSuperset_Reverts() (gas: 9600)
SortedSetValidationUtil_CheckIsValidUniqueSubsetTest:test__checkIsValidUniqueSubset_ValidSubset_Success() (gas: 6490)
7 changes: 5 additions & 2 deletions contracts/src/v0.8/ccip/capability/CCIPConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {ICapabilitiesRegistry} from "./interfaces/ICapabilitiesRegistry.sol";

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

import {SortedSetValidationUtil} from "../../shared/util/SortedSetValidationUtil.sol";
import {Internal} from "../libraries/Internal.sol";
import {CCIPConfigTypes} from "./libraries/CCIPConfigTypes.sol";

Expand Down Expand Up @@ -370,9 +371,11 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
}
if (cfg.bootstrapP2PIds.length > cfg.p2pIds.length) revert TooManyBootstrapP2PIds();

// check for duplicate p2p ids and bootstrapP2PIds.
// check that p2p ids in cfg.bootstrapP2PIds are included in cfg.p2pIds.
SortedSetValidationUtil._checkIsValidUniqueSubset(cfg.bootstrapP2PIds, cfg.p2pIds);

// 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) {
_ensureInRegistry(cfg.p2pIds[i]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ library CCIPConfigTypes {
uint8 F; // | The "big F" parameter for the role DON.
uint64 offchainConfigVersion; // ─────────────╯ The version of the offchain configuration.
bytes offrampAddress; // The remote chain offramp address.
// NOTE: bootstrapP2PIds and p2pIds should be sent as sorted sets
bytes32[] bootstrapP2PIds; // The bootstrap P2P IDs of the oracles that are part of the role DON.
// len(p2pIds) == len(signers) == len(transmitters) == 3 * F + 1
// NOTE: indexes matter here! The p2p ID at index i corresponds to the signer at index i and the transmitter at index i.
Expand Down
11 changes: 2 additions & 9 deletions contracts/src/v0.8/ccip/onRamp/EVM2EVMMultiOnRamp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre

/// @dev Struct to hold the configs for a destination chain
struct DestChainConfig {
DestChainDynamicConfig dynamicConfig; // ──╮ Dynamic configs for a destination chain
address prevOnRamp; // ────────────────────╯ Address of previous-version OnRamp
DestChainDynamicConfig dynamicConfig; // Dynamic configs for a destination chain
uint64 sequenceNumber; // The last used sequence number. This is zero in the case where no messages has been sent yet.
// 0 is not a valid sequence number for any real transaction.
/// @dev metadataHash is a lane-specific prefix for a message hash preimage which ensures global uniqueness
Expand All @@ -157,14 +156,12 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
bytes32 metadataHash;
}

/// @dev Struct to hold the dynamic configs, its destination chain selector and previous onRamp.
/// Same as DestChainConfig but with the destChainSelector and the prevOnRamp so that an array of these
/// @dev Struct to hold the dynamic configs, its destination chain selector. Same as DestChainConfig but with the destChainSelector so that an array of these
/// can be passed in the constructor and the applyDestChainConfigUpdates function
//solhint-disable gas-struct-packing
struct DestChainConfigArgs {
uint64 destChainSelector; // Destination chain selector
DestChainDynamicConfig dynamicConfig; // Struct to hold the configs for a destination chain
address prevOnRamp; // Address of previous-version OnRamp.
}

// STATIC CONFIG
Expand Down Expand Up @@ -761,11 +758,9 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
}

DestChainConfig storage destChainConfig = s_destChainConfig[destChainSelector];
address prevOnRamp = destChainConfigArg.prevOnRamp;

DestChainConfig memory newDestChainConfig = DestChainConfig({
dynamicConfig: destChainConfigArg.dynamicConfig,
prevOnRamp: prevOnRamp,
sequenceNumber: destChainConfig.sequenceNumber,
metadataHash: destChainConfig.metadataHash
});
Expand All @@ -776,11 +771,9 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
newDestChainConfig.metadataHash =
keccak256(abi.encode(Internal.EVM_2_ANY_MESSAGE_HASH, i_chainSelector, destChainSelector, address(this)));
destChainConfig.metadataHash = newDestChainConfig.metadataHash;
if (prevOnRamp != address(0)) destChainConfig.prevOnRamp = prevOnRamp;

emit DestChainAdded(destChainSelector, destChainConfig);
} else {
if (destChainConfig.prevOnRamp != prevOnRamp) revert InvalidDestChainConfig(destChainSelector);
if (destChainConfigArg.dynamicConfig.defaultTokenDestBytesOverhead < Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES) {
revert InvalidDestBytesOverhead(address(0), destChainConfigArg.dynamicConfig.defaultTokenDestBytesOverhead);
}
Expand Down
1 change: 0 additions & 1 deletion contracts/src/v0.8/ccip/test/NonceManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,6 @@ contract NonceManager_OnRampUpgrade is EVM2EVMMultiOnRampSetup {
s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps);

EVM2EVMMultiOnRamp.DestChainConfigArgs[] memory destChainConfigArgs = _generateDestChainConfigArgs();
destChainConfigArgs[0].prevOnRamp = address(s_prevOnRamp);

(s_onRamp, s_metadataHash) = _deployOnRamp(
SOURCE_CHAIN_SELECTOR, address(s_sourceRouter), address(s_outboundNonceManager), address(s_tokenAdminRegistry)
Expand Down
145 changes: 145 additions & 0 deletions contracts/src/v0.8/ccip/test/capability/CCIPConfig.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity ^0.8.24;

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

import {SortedSetValidationUtil} from "../../../shared/util/SortedSetValidationUtil.sol";
import {CCIPConfig} from "../../capability/CCIPConfig.sol";
import {ICapabilitiesRegistry} from "../../capability/interfaces/ICapabilitiesRegistry.sol";
import {CCIPConfigTypes} from "../../capability/libraries/CCIPConfigTypes.sol";
Expand Down Expand Up @@ -44,11 +45,31 @@ contract CCIPConfigSetup is Test {
return subset;
}

//TODO: Use OZ's Arrays.sort when we upgrade to OZ v5
function _sort(bytes32[] memory arr, int256 left, int256 right) private pure {
int256 i = left;
int256 j = right;
if (i == j) return;
bytes32 pivot = arr[uint256(left + (right - left) / 2)];
while (i <= j) {
while (arr[uint256(i)] < pivot) i++;
while (pivot < arr[uint256(j)]) j--;
if (i <= j) {
(arr[uint256(i)], arr[uint256(j)]) = (arr[uint256(j)], arr[uint256(i)]);
i++;
j--;
}
}
if (left < j) _sort(arr, left, j);
if (i < right) _sort(arr, i, right);
}

function _addChainConfig(uint256 numNodes)
internal
returns (bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters)
{
p2pIds = _makeBytes32Array(numNodes, 0);
_sort(p2pIds, 0, int256(numNodes - 1));
signers = _makeBytesArray(numNodes, 10);
transmitters = _makeBytesArray(numNodes, 20);
for (uint256 i = 0; i < numNodes; i++) {
Expand Down Expand Up @@ -536,6 +557,130 @@ contract CCIPConfig_validateConfig is CCIPConfigSetup {
vm.expectRevert(abi.encodeWithSelector(CCIPConfig.NodeNotInRegistry.selector, nonExistentP2PId));
s_ccipCC.validateConfig(config);
}

function test__validateConfig_P2PIdsNotSorted_Reverts() public {
(bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
// Config is for 4 nodes, so f == 1.

//swapping two adjacent p2pIds to make it unsorted
(p2pIds[2], p2pIds[3]) = (p2pIds[3], p2pIds[2]);

CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
pluginType: Internal.OCRPluginType.Commit,
offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
chainSelector: 1,
bootstrapP2PIds: _subset(p2pIds, 0, 1),
p2pIds: p2pIds,
signers: signers,
transmitters: transmitters,
F: 1,
offchainConfigVersion: 30,
offchainConfig: bytes("offchainConfig")
});

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, p2pIds));
s_ccipCC.validateConfig(config);
}

function test__validateConfig_BootstrapP2PIdsNotSorted_Reverts() public {
(bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
// Config is for 4 nodes, so f == 1.

bytes32[] memory bootstrapP2PIds = _subset(p2pIds, 0, 2);

//swapping bootstrapP2PIds to make it unsorted
(bootstrapP2PIds[0], bootstrapP2PIds[1]) = (bootstrapP2PIds[1], bootstrapP2PIds[0]);

CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
pluginType: Internal.OCRPluginType.Commit,
offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
chainSelector: 1,
bootstrapP2PIds: bootstrapP2PIds,
p2pIds: p2pIds,
signers: signers,
transmitters: transmitters,
F: 1,
offchainConfigVersion: 30,
offchainConfig: bytes("offchainConfig")
});

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, bootstrapP2PIds));
s_ccipCC.validateConfig(config);
}

function test__validateConfig_P2PIdsHasDuplicates_Reverts() public {
(bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
// Config is for 4 nodes, so f == 1.

//forcing duplicate p2pIds
p2pIds[1] = p2pIds[2];

CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
pluginType: Internal.OCRPluginType.Commit,
offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
chainSelector: 1,
bootstrapP2PIds: _subset(p2pIds, 0, 2),
p2pIds: p2pIds,
signers: signers,
transmitters: transmitters,
F: 1,
offchainConfigVersion: 30,
offchainConfig: bytes("offchainConfig")
});

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, p2pIds));
s_ccipCC.validateConfig(config);
}

function test__validateConfig_BootstrapP2PIdsHasDuplicates_Reverts() public {
(bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
// Config is for 4 nodes, so f == 1.

bytes32[] memory bootstrapP2PIds = _subset(p2pIds, 0, 2);
//forcing duplicate bootstrapP2PIds
bootstrapP2PIds[1] = bootstrapP2PIds[0];

CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
pluginType: Internal.OCRPluginType.Commit,
offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
chainSelector: 1,
bootstrapP2PIds: bootstrapP2PIds,
p2pIds: p2pIds,
signers: signers,
transmitters: transmitters,
F: 1,
offchainConfigVersion: 30,
offchainConfig: bytes("offchainConfig")
});

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASortedSet.selector, bootstrapP2PIds));
s_ccipCC.validateConfig(config);
}

function test__validateConfig_BootstrapP2PIdsNotASubsetOfP2PIds_Reverts() public {
(bytes32[] memory p2pIds, bytes[] memory signers, bytes[] memory transmitters) = _addChainConfig(4);
// Config is for 4 nodes, so f == 1.

//forcing invalid bootstrapP2PIds where the bootstrapP2PIds is sorted, but one of the element is not in the p2pIdsSet
bytes32[] memory bootstrapP2PIds = _subset(p2pIds, 0, 2);
p2pIds[1] = bytes32(uint256(p2pIds[0]) + 100);

CCIPConfigTypes.OCR3Config memory config = CCIPConfigTypes.OCR3Config({
pluginType: Internal.OCRPluginType.Commit,
offrampAddress: abi.encodePacked(keccak256(abi.encode("offramp"))),
chainSelector: 1,
bootstrapP2PIds: bootstrapP2PIds,
p2pIds: p2pIds,
signers: signers,
transmitters: transmitters,
F: 1,
offchainConfigVersion: 30,
offchainConfig: bytes("offchainConfig")
});

vm.expectRevert(abi.encodeWithSelector(SortedSetValidationUtil.NotASubset.selector, bootstrapP2PIds, p2pIds));
s_ccipCC.validateConfig(config);
}
}

contract CCIPConfig_ConfigStateMachine is CCIPConfigSetup {
Expand Down
Loading

0 comments on commit 67bc739

Please sign in to comment.