Skip to content

Commit

Permalink
[CCIP-3360] contracts/src/v0.8/ccip: merge latest changes from the cc…
Browse files Browse the repository at this point in the history
…ip repo (#14345)

* Misc golfs and fixes (#1402)

Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>

* Increase max signers (#1405)

Improve tests and error checks

---------

Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>

* rename CCIPSendRequested to CCIPMessageSent (#1409)

* Skip report execution on curse (#1408)

## Motivation

The goal of this PR is to remove reverts on lane cursing for DON
execution transactions. If a lane is cursed, reverting will cause the
whole execution transaction to fail so any execution reports for other
lanes will be blocked.

## Solution

For DON execution transactions the behavior is now to skip the report
and emit a `SkippedReportExecution`. For manual execution we still
revert, otherwise the transaction will silently fail for the users.

---------

Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>

* remove bootstrapP2PIds (#1388)

## Motivation

Bootstrap P2P IDs are no longer needed in the OCR config in CCIPConfig.
See #1348's description for more details.

## Solution

Remove bootstrap P2P IDs from the OCR config in CCIPConfig.

## Related PRs
smartcontractkit/chainlink-ccip#89

* fixes

* Integrate RMNRemote and OffRamp (#1360)

Remove the requirement for self-transmitted RMN blessings

Allow the commit DON to include RMN blessings at commitment time
This PR has a dependency on changes to
[chainlink-ccip](smartcontractkit/chainlink-ccip#84)

---------

Co-authored-by: Makram <makramkd@users.noreply.github.com>

* contracts/scripts: reduce offramp optimizations (#1414)

## Motivation

The offramp was failing to deploy due to too many optimizations causing
a max code size exceeded error.

## Solution

Reduce the number of optimizations by 1.

Also, add a test that deploys v1.6 contracts and ensures that they are
deployable on the simulated backend.

* more fixes

* remove isBlessed from contract reader cfg

* deploy RMNRemote instead of MockRMN

* bump chainlink-ccip

* bump chainlink-ccip and add changesets

---------

Co-authored-by: Rens Rooimans <github@rensrooimans.nl>
Co-authored-by: app-token-issuer-infra-releng[bot] <120227048+app-token-issuer-infra-releng[bot]@users.noreply.github.com>
Co-authored-by: Suryansh <39276431+0xsuryansh@users.noreply.github.com>
Co-authored-by: Ryan <80392855+RayXpub@users.noreply.github.com>
Co-authored-by: Ryan Hall <RyanRHall@users.noreply.github.com>
  • Loading branch information
6 people authored Sep 5, 2024
1 parent 9ce13a1 commit c83c687
Show file tree
Hide file tree
Showing 59 changed files with 2,373 additions and 1,518 deletions.
5 changes: 5 additions & 0 deletions .changeset/plenty-glasses-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#internal merge ccip contracts
5 changes: 5 additions & 0 deletions contracts/.changeset/flat-turkeys-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/contracts': patch
---

#internal merge ccip contracts
3 changes: 1 addition & 2 deletions contracts/.solhintignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,4 @@
./node_modules/

# Ignore RMN contracts temporarily
./src/v0.8/ccip/RMNRemote.sol
./src/v0.8/ccip/RMNHome.sol
./src/v0.8/ccip/rmn
815 changes: 403 additions & 412 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"moment": "^2.30.1",
"prettier": "^3.3.3",
"prettier-plugin-solidity": "^1.3.1",
"solhint": "^5.0.3",
"solhint": "^5.0.1",
"solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.1",
"solhint-plugin-prettier": "^0.1.0",
"ts-node": "^10.9.2",
Expand Down
22 changes: 14 additions & 8 deletions contracts/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion contracts/scripts/native_solc_compile_all_ccip
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SOLC_VERSION="0.8.24"
OPTIMIZE_RUNS=26000
OPTIMIZE_RUNS_OFFRAMP=18000
OPTIMIZE_RUNS_ONRAMP=4100
OPTIMIZE_RUNS_MULTI_OFFRAMP=2000
OPTIMIZE_RUNS_MULTI_OFFRAMP=1999


SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
Expand Down Expand Up @@ -59,6 +59,7 @@ compileContract () {
# Contracts should be ordered in reverse-import-complexity-order to minimize overwrite risks.
compileContract ccip/offRamp/EVM2EVMOffRamp.sol
compileContract ccip/offRamp/OffRamp.sol
compileContract ccip/rmn/RMNRemote.sol
compileContract ccip/applications/PingPongDemo.sol
compileContract ccip/applications/SelfFundedPingPong.sol
compileContract ccip/applications/EtherSenderReceiver.sol
Expand Down
6 changes: 2 additions & 4 deletions contracts/src/v0.8/ccip/FeeQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,6 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
uint256 numberOfTokens = message.tokenAmounts.length;
_validateMessage(destChainConfig, message.data.length, numberOfTokens, message.receiver);

uint64 premiumMultiplierWeiPerEth = s_premiumMultiplierWeiPerEth[message.feeToken];

// The below call asserts that feeToken is a supported token
(uint224 feeTokenPrice, uint224 packedGasPrice) = getTokenAndGasPrices(message.feeToken, destChainSelector);

Expand Down Expand Up @@ -511,7 +509,6 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,

// NOTE: when supporting non-EVM chains, revisit how generic this fee logic can be
// NOTE: revisit parsing non-EVM args

uint256 executionCost = uint112(packedGasPrice)
* (
destChainConfig.destGasOverhead + (message.data.length * destChainConfig.destGasPerPayloadByte) + tokenTransferGas
Expand All @@ -521,7 +518,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
// Calculate number of fee tokens to charge.
// Total USD fee is in 36 decimals, feeTokenPrice is in 18 decimals USD for 1e18 smallest token denominations.
// Result of the division is the number of smallest token denominations.
return ((premiumFee * premiumMultiplierWeiPerEth) + executionCost + dataAvailabilityCost) / feeTokenPrice;
return ((premiumFee * s_premiumMultiplierWeiPerEth[message.feeToken]) + executionCost + dataAvailabilityCost)
/ feeTokenPrice;
}

/// @notice Sets the fee configuration for a token.
Expand Down
74 changes: 29 additions & 45 deletions contracts/src/v0.8/ccip/capability/CCIPConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
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 All @@ -26,7 +24,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
/// @param chainSelector The chain selector.
/// @param chainConfig The chain configuration.
event ChainConfigSet(uint64 chainSelector, CCIPConfigTypes.ChainConfig chainConfig);

/// @notice Emitted when a chain's configuration is removed.
/// @param chainSelector The chain selector.
event ChainConfigRemoved(uint64 chainSelector);
Expand All @@ -37,8 +34,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
error ChainSelectorNotSet();
error TooManyOCR3Configs();
error TooManySigners();
error TooManyTransmitters();
error TooManyBootstrapP2PIds();
error P2PIdsLengthNotMatching(uint256 p2pIdsLength, uint256 signersLength, uint256 transmittersLength);
error NotEnoughTransmitters(uint256 got, uint256 minimum);
error FMustBePositive();
Expand All @@ -62,6 +57,15 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
/// @notice The canonical capabilities registry address.
address internal immutable i_capabilitiesRegistry;

uint8 internal constant MAX_OCR3_CONFIGS_PER_PLUGIN = 2;
uint8 internal constant MAX_OCR3_CONFIGS_PER_DON = 4;
uint256 internal constant CONFIG_DIGEST_PREFIX_MASK = type(uint256).max << (256 - 16); // 0xFFFF00..0
/// @dev must be equal to libocr multi role: https://github.com/smartcontractkit/libocr/blob/ae747ca5b81236ffdbf1714318c652e923a5ff4d/offchainreporting2plus/types/config_digest.go#L28
uint256 internal constant CONFIG_DIGEST_PREFIX = 0x000a << (256 - 16); // 0x000a00..00
bytes32 internal constant EMPTY_ENCODED_ADDRESS_HASH = keccak256(abi.encode(address(0)));
/// @dev 256 is the hard limit due to the bit encoding of their indexes into a uint256.
uint256 internal constant MAX_NUM_ORACLES = 256;

/// @notice chain configuration for each chain that CCIP is deployed on.
mapping(uint64 chainSelector => CCIPConfigTypes.ChainConfig chainConfig) internal s_chainConfigurations;

Expand All @@ -75,13 +79,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
uint32 donId => mapping(Internal.OCRPluginType pluginType => CCIPConfigTypes.OCR3ConfigWithMeta[] ocr3Configs)
) internal s_ocr3Configs;

uint8 internal constant MAX_OCR3_CONFIGS_PER_PLUGIN = 2;
uint8 internal constant MAX_OCR3_CONFIGS_PER_DON = 4;
uint8 internal constant MAX_NUM_ORACLES = 31;
uint256 internal constant CONFIG_DIGEST_PREFIX_MASK = type(uint256).max << (256 - 16); // 0xFFFF00..0
/// @dev must be equal to libocr multi role: https://github.com/smartcontractkit/libocr/blob/ae747ca5b81236ffdbf1714318c652e923a5ff4d/offchainreporting2plus/types/config_digest.go#L28
uint256 internal constant CONFIG_DIGEST_PREFIX = 0x000a << (256 - 16); // 0x000a00..00

/// @param capabilitiesRegistry the canonical capabilities registry address.
constructor(address capabilitiesRegistry) {
if (capabilitiesRegistry == address(0)) {
Expand Down Expand Up @@ -172,9 +169,8 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
revert OnlyCapabilitiesRegistryCanCall();
}

CCIPConfigTypes.OCR3Config[] memory ocr3Configs = abi.decode(config, (CCIPConfigTypes.OCR3Config[]));
(CCIPConfigTypes.OCR3Config[] memory commitConfigs, CCIPConfigTypes.OCR3Config[] memory execConfigs) =
_groupByPluginType(ocr3Configs);
_groupByPluginType(abi.decode(config, (CCIPConfigTypes.OCR3Config[])));
if (commitConfigs.length > 0) {
_updatePluginConfig(donId, Internal.OCRPluginType.Commit, commitConfigs);
}
Expand Down Expand Up @@ -363,8 +359,8 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
// access in the for loop below.
commitConfigs = new CCIPConfigTypes.OCR3Config[](MAX_OCR3_CONFIGS_PER_PLUGIN);
execConfigs = new CCIPConfigTypes.OCR3Config[](MAX_OCR3_CONFIGS_PER_PLUGIN);
uint256 commitCount;
uint256 execCount;
uint256 commitCount = 0;
uint256 execCount = 0;
for (uint256 i = 0; i < ocr3Configs.length; ++i) {
if (ocr3Configs[i].pluginType == Internal.OCRPluginType.Commit) {
commitConfigs[commitCount] = ocr3Configs[i];
Expand All @@ -391,36 +387,26 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
if (cfg.pluginType != Internal.OCRPluginType.Commit && cfg.pluginType != Internal.OCRPluginType.Execution) {
revert InvalidPluginType();
}
// TODO: can we do more sophisticated validation than this?
if (cfg.offrampAddress.length == 0) revert OfframpAddressCannotBeZero();
if (cfg.offrampAddress.length == 0 || keccak256(cfg.offrampAddress) == EMPTY_ENCODED_ADDRESS_HASH) {
revert OfframpAddressCannotBeZero();
}
if (!s_remoteChainSelectors.contains(cfg.chainSelector)) revert ChainSelectorNotFound(cfg.chainSelector);

// Some of these checks below are done in OCR2/3Base config validation, so we do them again here.
// Role DON OCR configs will have all the Role DON signers but only a subset of transmitters.
if (cfg.signers.length > MAX_NUM_ORACLES) revert TooManySigners();
if (cfg.transmitters.length > MAX_NUM_ORACLES) revert TooManyTransmitters();

// We check for chain config presence above, so fChain here must be non-zero.
uint256 minTransmittersLength = 3 * s_chainConfigurations[cfg.chainSelector].fChain + 1;
if (cfg.transmitters.length < minTransmittersLength) {
revert NotEnoughTransmitters(cfg.transmitters.length, minTransmittersLength);
}
if (cfg.F == 0) revert FMustBePositive();
if (cfg.signers.length <= 3 * cfg.F) revert FTooHigh();

if (cfg.p2pIds.length != cfg.signers.length || cfg.p2pIds.length != cfg.transmitters.length) {
uint256 numberOfSigners = cfg.signers.length;
if (numberOfSigners > MAX_NUM_ORACLES) revert TooManySigners();
if (numberOfSigners != cfg.p2pIds.length || numberOfSigners != cfg.transmitters.length) {
revert P2PIdsLengthNotMatching(cfg.p2pIds.length, cfg.signers.length, cfg.transmitters.length);
}
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);
if (cfg.F == 0) revert FMustBePositive();
if (numberOfSigners <= 3 * cfg.F) revert FTooHigh();

// Check that the readers are in the capabilities registry.
for (uint256 i = 0; i < cfg.signers.length; ++i) {
_ensureInRegistry(cfg.p2pIds[i]);
}
_ensureInRegistry(cfg.p2pIds);
}

/// @notice Computes the digest of the provided configuration.
Expand All @@ -445,7 +431,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
ocr3Config.pluginType,
ocr3Config.offrampAddress,
configCount,
ocr3Config.bootstrapP2PIds,
ocr3Config.p2pIds,
ocr3Config.signers,
ocr3Config.transmitters,
Expand Down Expand Up @@ -486,13 +471,10 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
// Process additions next.
for (uint256 i = 0; i < chainConfigAdds.length; ++i) {
CCIPConfigTypes.ChainConfig memory chainConfig = chainConfigAdds[i].chainConfig;
bytes32[] memory readers = chainConfig.readers;
uint64 chainSelector = chainConfigAdds[i].chainSelector;

// Verify that the provided readers are present in the capabilities registry.
for (uint256 j = 0; j < readers.length; j++) {
_ensureInRegistry(readers[j]);
}
_ensureInRegistry(chainConfig.readers);

// Verify that fChain is positive.
if (chainConfig.fChain == 0) {
Expand All @@ -507,11 +489,13 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
}

/// @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 {
ICapabilitiesRegistry.NodeInfo memory node = ICapabilitiesRegistry(i_capabilitiesRegistry).getNode(p2pId);
if (node.p2pId == bytes32("")) {
revert NodeNotInRegistry(p2pId);
/// @param p2pIds The P2P IDs of the node to check.
function _ensureInRegistry(bytes32[] memory p2pIds) internal view {
for (uint256 i = 0; i < p2pIds.length; ++i) {
// TODO add a method that does the validation in the ICapabilitiesRegistry contract
if (ICapabilitiesRegistry(i_capabilitiesRegistry).getNode(p2pIds[i]).p2pId == bytes32("")) {
revert NodeNotInRegistry(p2pIds[i]);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ 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.
// This is crucial in order to build the oracle ID <-> peer ID mapping offchain.
Expand Down
22 changes: 22 additions & 0 deletions contracts/src/v0.8/ccip/interfaces/IRMNV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Internal} from "../libraries/Internal.sol";

/// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts.
interface IRMNV2 {
/// @notice signature components from RMN nodes
struct Signature {
bytes32 r;
bytes32 s;
}

function verify(Internal.MerkleRoot[] memory merkleRoots, Signature[] memory signatures) external view;

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

/// @notice If 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);
}
10 changes: 10 additions & 0 deletions contracts/src/v0.8/ccip/libraries/Internal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -338,4 +338,14 @@ library Internal {

// bytes4(keccak256("CCIP ChainFamilySelector EVM"))
bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;

/// @dev Struct to hold a merkle root and an interval for a source chain so that an array of these can be passed in the CommitReport.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct MerkleRoot {
uint64 sourceChainSelector; // ──╮ Remote source chain selector that the Merkle Root is scoped to
uint64 minSeqNr; // | Minimum sequence number, inclusive
uint64 maxSeqNr; // ─────────────╯ Maximum sequence number, inclusive
bytes32 merkleRoot; // Merkle root covering the interval & source chain messages
bytes onRampAddress; // Generic onramp address, to support arbitrary sources; for EVM, use abi.encode
}
}
Loading

0 comments on commit c83c687

Please sign in to comment.