Retry Management

Message Retry Overview

The regular flow of a message involves sending a message from a source contract/chain to a destination contract/chain.

Sometimes a message could remain in a pending delivery status within a GMP for an indeterminate lapse and not be delivered to destination on the expected time.

At this moment it could be suspected that the GMP is in a downtime state and (if the message is of high priority) it would be of interest to retry sending the message (usually using a different GMP) to try to reach the destination through other routes as soon as possible.

However the retry operation can present some issues

Message Retrying Potential Issues

The main potential issues when retrying messages are:

  • Message Duplication

  • Replay Attack

Message Duplication

Given the previously mentioned conditions, it might happen that, after the retried message arrives at destination, the previous stalled message is finally released by the initial GMP to the destination as well, in which case a duplicated message would be received (a kind of double spend).

Replay Attack

Again with the previously mentioned conditions a malicious actor in the GMP network could have intercepted our retry message and resend it with different payload as a retry intent.

Glacis Retry Management Feature

As Glacis is a pure on-chain protocol it cannot initiate the retrying of a message automatically by itself, but it offers a retry management feature to allow applications to retry the sending of a message without any of the potential issues of retrying methods.

If an application wants to retry a message it must first perform an initial routing with "retriable" parameter as true using the route function of Glacis Router.

    function route(
        uint256 chainId,
        address to,
        bytes memory payload,
        uint8[] memory gmps,
        uint256[] memory fees,
        address refundAddress,
        bool retriable
    ) public payable virtual returns (bytes32)

This activates Glacis retry management feature at Glacis source infrastructure, which causes (among other things) the emission of a MessageIdCreated event with the following event parameters:

  • MessageId: The calculated unique Glacis message identification

  • nonce: A unique accumulated number for each Message Id creation

The application needs to subscribe to this event and extract and store these event parameters since the messageId and nonce are required for routing retrying.

If the application detects that a message did not arrive at destination in time and wants to retry sending the message it can do it through the use of retryRoute function specifying all the routing parameters plus the messageId and nonce of the message that wants to be retried.

    function routeRetry(
        uint256 chainId,
        address to,
        bytes memory payload,
        uint8[] memory gmps,
        uint256[] memory fees,
        address refundAddress,
        bytes32 messageId,
        uint256 nonce
    ) public payable virtual returns (bytes32) 

Retry Managed Duplicated Message

When using Glacis retry management feature, duplicated messages will be reverted once the first one of the retried messages is delivered to the final destination.

Retry Managed Replay Attack

When utilizing the Glacis retry management feature, if the origin of the retry is different than the initial routing, the retrying operation will be reverted.

Retry Managed Same Origin Replay Attack

When utilizing the Glacis retry management feature, if the recalculated messageID for a retried message differs from the original messageID, the retrying operation will be reverted.

The calculation of the message id takes into account both the routing parameters and the payload sent.

Retry Management Mechanism

The mechanism by which Glacis avoids duplicate messages when retrying happens in the GlacisRouter.

In source chain

When the application executes the route() function with a message with retry management enabled, the following tasks are performed by the router:

  1. Increment a unique nonce that is then added to the message payload

  2. Create a message Id that includes the routing parameters along with payload hash, message sender and nonce

  3. Register the msg.sender of this messageId:

Then when the application issues routeRetry() with messageId and nonce along with the routing parameters and payload the following controls are performed:

  1. Validate that the retrying sender is the same that originally routed.

  2. Validate that the messageId calculated with the all passed parameters is equal to the informed one.

If all checks pass, the retry can be performed, the payload is created and the message delivered to the requested GMP protocols through the corresponding adapters.

In destination chain

Upon the reception of a message from a GMP, the receiveMessage() function is executed, performing the following tasks:

  1. Extract the message receipts for this messageId.

  2. Validate there are no previous receipts for this messageId for each requested GMP.

  3. Validate that the messageId calculated with all passed parameters is equal to the informed one.

If all checks pass, increase the number of unique messages received for this messageId and GMP and deliver the message to destination.

Last updated