-
Notifications
You must be signed in to change notification settings - Fork 13
Description
Currently, when delivering a message to a destination application, the delivery is placed through a try-catch statement. It looks roughly like this:
try ICrossChainReceiver(toApplication).receiveMessage{gas: maxGas}(sourceIdentifier, messageIdentifier, fromApplication, message[CTX0_MESSAGE_START: ])
returns (bytes memory ack) {
acknowledgement = ack;
} catch (bytes memory /* err */) {
acknowledgement = abi.encodePacked(
MESSAGE_REVERTED,
message[CTX0_MESSAGE_START: ]
);
}Ideally, this would ensure that if anything goes wrong, out of gas, the exception raised, incorrectly configured contract, return bombs, you name it, it would be caught and execution can continue. This would greatly simplify relayer design and relaying assumptions.
However, that is not the case. Solidity has an open issue on the topic: argotorg/solidity#13869 and it also contains a list of cases where Solidity doesn't catch an error.
One solution would be to change the implementation to:
(bool success, bytes memory returndata) = toApplication.call{gas: maxGas}(abi.encodeWithSignature(....));
if (success) {
(acknowledgement) = abi.decode(returndata, (bytes));
} else {
acknowledgement = abi.encodePacked(
MESSAGE_REVERTED,
message[CTX0_MESSAGE_START: ]
);
}But abi.decode can fail if the application doesn't return the expected format which is "[location, length, bytes]". In theory, it is possible to check that the returndata is longer than 64 bytes + length but this adds complexity and gas cost. It also won't protect against return bombs.