Skip to content

Return data abuse results in non-deliverable messages #8

@reednaa

Description

@reednaa

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions