Skip to content

Commit

Permalink
fix: CCIP-2950 gasLimitOverride fixes for tests
Browse files Browse the repository at this point in the history
  • Loading branch information
defistar committed Aug 7, 2024
1 parent 3891da0 commit d187fe5
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 6 deletions.
19 changes: 19 additions & 0 deletions contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ contract EVM2EVMOffRamp is IAny2EVMOffRamp, AggregateRateLimiter, ITypeAndVersio
error UnsupportedNumberOfTokens(uint64 sequenceNumber);
error ManualExecutionNotYetEnabled();
error ManualExecutionGasLimitMismatch();
error DestinationGasAmountCountMismatch(bytes32 messageId, uint64 sequenceNumber);
error InvalidManualExecutionGasLimit(uint256 index, uint256 newLimit);
error InvalidDestGasAmount(uint256 index, uint256 destGasAmount);
error RootNotCommitted();
error CanOnlySelfCall();
error ReceiverError(bytes err);
Expand Down Expand Up @@ -239,6 +241,23 @@ contract EVM2EVMOffRamp is IAny2EVMOffRamp, AggregateRateLimiter, ITypeAndVersio
revert InvalidManualExecutionGasLimit(i, newLimit);
}
}

if (report.messages[i].tokenAmounts.length != gasLimitOverrides[i].destGasAmounts.length) {
revert DestinationGasAmountCountMismatch(report.messages[i].messageId, report.messages[i].sequenceNumber);
}

bytes[] memory encodedSourceTokenData = report.messages[i].sourceTokenData;

for (uint256 j = 0; j < report.messages[i].tokenAmounts.length; ++j) {
Internal.SourceTokenData memory sourceTokenData =
abi.decode(encodedSourceTokenData[i], (Internal.SourceTokenData));
uint256 destGasAmount = gasLimitOverrides[i].destGasAmounts[j];
if (destGasAmount != 0) {
if (destGasAmount < sourceTokenData.destGasAmount) {
revert InvalidDestGasAmount(j, destGasAmount);
}
}
}
}

_execute(report, gasLimitOverrides);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {EVM2EVMOffRamp} from "../../../offRamp/EVM2EVMOffRamp.sol";
contract ReentrancyAbuser is CCIPReceiver {
event ReentrancySucceeded();

uint32 internal constant DEFAULT_TOKEN_DEST_GAS_OVERHEAD = 144_000;

bool internal s_ReentrancyDone = false;
Internal.ExecutionReport internal s_payload;
EVM2EVMOffRamp internal s_offRamp;
Expand All @@ -24,7 +26,7 @@ contract ReentrancyAbuser is CCIPReceiver {
function _ccipReceive(Client.Any2EVMMessage memory) internal override {
// Use original message gas limits in manual execution
uint256 numMsgs = s_payload.messages.length;
EVM2EVMOffRamp.GasLimitOverride[] memory gasOverrides = new EVM2EVMOffRamp.GasLimitOverride[](numMsgs);
EVM2EVMOffRamp.GasLimitOverride[] memory gasOverrides = _getGasLimitsFromMessages(s_payload.messages);

if (!s_ReentrancyDone) {
// Could do more rounds but a PoC one is enough
Expand All @@ -34,4 +36,24 @@ contract ReentrancyAbuser is CCIPReceiver {
emit ReentrancySucceeded();
}
}

function _getGasLimitsFromMessages(Internal.EVM2EVMMessage[] memory messages)
internal
view
returns (EVM2EVMOffRamp.GasLimitOverride[] memory)
{
EVM2EVMOffRamp.GasLimitOverride[] memory gasLimitOverrides = new EVM2EVMOffRamp.GasLimitOverride[](messages.length);
for (uint256 i = 0; i < messages.length; ++i) {
gasLimitOverrides[i].receiverExecutionGasLimit = messages[i].gasLimit;
//create an array for destinationGasAmounts
gasLimitOverrides[i].destGasAmounts = new uint256[](messages[i].tokenAmounts.length);

// initialize destGasAmounts
for (uint256 j = 0; j < messages[i].tokenAmounts.length; ++j) {
gasLimitOverrides[i].destGasAmounts[j] = DEFAULT_TOKEN_DEST_GAS_OVERHEAD + 1;
}
}

return gasLimitOverrides;
}
}
3 changes: 2 additions & 1 deletion contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRamp.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1204,7 +1204,8 @@ contract EVM2EVMOffRamp_manuallyExecute is EVM2EVMOffRampSetup {
messages[0].sequenceNumber, messages[0].messageId, Internal.MessageExecutionState.SUCCESS, ""
);

s_offRamp.manuallyExecute(report, _getGasLimitsFromMessages(messages));
EVM2EVMOffRamp.GasLimitOverride[] memory gasLimits = _getGasLimitsFromMessages(messages);
s_offRamp.manuallyExecute(report, gasLimits);

// Assert that they only got the tokens once, not twice
assertEq(tokenToAbuse.balanceOf(address(receiver)), balancePre + tokenAmount);
Expand Down
20 changes: 16 additions & 4 deletions contracts/src/v0.8/ccip/test/offRamp/EVM2EVMOffRampSetup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {OCR2BaseSetup} from "../ocr/OCR2Base.t.sol";
import {PriceRegistrySetup} from "../priceRegistry/PriceRegistry.t.sol";

import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import "forge-std/console.sol";

contract EVM2EVMOffRampSetup is TokenSetup, PriceRegistrySetup, OCR2BaseSetup {
MockCommitStore internal s_mockCommitStore;
Expand Down Expand Up @@ -191,6 +190,15 @@ contract EVM2EVMOffRampSetup is TokenSetup, PriceRegistrySetup, OCR2BaseSetup {
return messages;
}

function _generateSingleBasicMessageWithTokens() internal view returns (Internal.EVM2EVMMessage[] memory) {
Internal.EVM2EVMMessage[] memory messages = new Internal.EVM2EVMMessage[](2);
Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
tokenAmounts[0].amount = 1e18;
tokenAmounts[1].amount = 5e18;
messages[0] = _generateAny2EVMMessage(1, tokenAmounts, false);
return messages;
}

function _generateMessagesWithTokens() internal view returns (Internal.EVM2EVMMessage[] memory) {
Internal.EVM2EVMMessage[] memory messages = new Internal.EVM2EVMMessage[](2);
Client.EVMTokenAmount[] memory tokenAmounts = getCastedSourceEVMTokenAmountsWithZeroAmounts();
Expand Down Expand Up @@ -223,29 +231,33 @@ contract EVM2EVMOffRampSetup is TokenSetup, PriceRegistrySetup, OCR2BaseSetup {

function _getGasLimitsFromMessages(Internal.EVM2EVMMessage[] memory messages)
internal
pure
view
returns (EVM2EVMOffRamp.GasLimitOverride[] memory)
{
EVM2EVMOffRamp.GasLimitOverride[] memory gasLimitOverrides = new EVM2EVMOffRamp.GasLimitOverride[](messages.length);
for (uint256 i = 0; i < messages.length; ++i) {
gasLimitOverrides[i].receiverExecutionGasLimit = messages[i].gasLimit;
//create an array for destinationGasAmounts
gasLimitOverrides[i].destGasAmounts = new uint256[](messages[i].tokenAmounts.length);

// initialize destGasAmounts
for (uint256 j = 0; j < messages[i].tokenAmounts.length; ++j) {
gasLimitOverrides[i].destGasAmounts[j] = DEFAULT_TOKEN_DEST_GAS_OVERHEAD + 1;
}
}

return gasLimitOverrides;
}

function _prepareInvalidGasLimitsFromMessages(Internal.EVM2EVMMessage[] memory messages)
internal
pure
returns (EVM2EVMOffRamp.GasLimitOverride[] memory)
{
EVM2EVMOffRamp.GasLimitOverride[] memory gasLimitOverrides = new EVM2EVMOffRamp.GasLimitOverride[](messages.length);
for (uint256 i = 0; i < messages.length; ++i) {
gasLimitOverrides[i].receiverExecutionGasLimit = messages[i].gasLimit;
console.log("tokenAmounts length is: ", messages[i].tokenAmounts.length);
gasLimitOverrides[i].destGasAmounts = new uint256[](messages[i].tokenAmounts.length - 1);
console.log("destGasAmounts array length after reduction is: ", gasLimitOverrides[i].destGasAmounts.length);
}

return gasLimitOverrides;
Expand Down

0 comments on commit d187fe5

Please sign in to comment.