Verified: the destination chain has received verification from all configured DVNs and the message nonce has been committed to the Endpoint’s messaging channel.
Delivered: the message has been successfully executed by the Executor.
Because verification and execution are separate, LayerZero can provide specific error handling for each message state.
General debugging steps can be found here.
Message Execution
When your message is successfully delivered to the destination chain, the protocol attempts to execute the message with the execution parameters defined by the sender. Message execution can result in two possible states:-
Success: If the execution is successful, an event (
PacketReceived) is emitted. -
Failure: If the execution fails, the contract reverses the clearing of the payload (re-inserts the payload) and emits an event (
LzReceiveAlert) to signal the failure.- Out of Gas: The message fails because the transaction that contains the message doesn’t provide enough gas for execution. The Message Execution Options applied to a message can be viewed on LayerZero Scan. There are several ways to determine the optimal gas values for these options. See Determining Gas Costs for more details.
- Logic Error: There’s an error in either the contract code or the message parameters passed that prevents the message from being executed correctly.
Retry Message
Because LayerZero separates the verification of a message from its execution, if a message fails to execute due to either of the reasons above, the message can be retried without having to resend it from the origin chain. This is possible because the message has already been confirmed by the DVNs as a valid message packet, meaning execution can be retried at anytime, by anyone. Here’s how an OApp contract owner or user can retry a message:- Using LayerZero Scan: For users that want a simple frontend interface to interact with, LayerZero Scan provides both message failure detection and in-browser message retrying.
-
Calling
lzReceiveDirectly: If message execution fails, any user can retry the call on the Endpoint’slzReceivefunction via the block explorer or any popular library for interacting with the blockchain like ethers, viem, etc.
lzReceive() - Receive Messages
Note: In the event of anlzCompose failure, the resolution process is similar. Any user can simply retry the call by invoking the Endpoint’s lzCompose function.
lzCompose() - Execute Compose Messages
Skipping Nonce
Occasionally, an OApp delegate may want to cancel the verification of an in-flight message. This might be due to a variety of reasons, such as:- Race Conditions: conditions where multiple transactions are being processed in parallel, and some might become invalid or redundant before they are processed.
- Error Handling: In scenarios where a message cannot be delivered (for example, due to being invalid or because prerequisites are not met), the skip function provides a way to bypass it and continue with subsequent messages.
An OApp’s delegate can call the
skip method via the Endpoint to stop message delivery:
skip()
Example for callingskip
- Set up Dependencies and Define the ABI
- Configure the Contract Instance
- Prepare Function Parameters
- Send the Transaction
Clearing Message
As a last resort, an OApp contract owner may want to force eject a message packet, either due to an unrecoverable error or to prevent a malicious packet from being executed:- When logic errors exist and the message can’t be retried successfully.
- When a malicious message needs to be avoided.
clear Function: This function exists on the Endpoint and allows an OApp contract delegate to burn the message payload so it can never be retried again.
clear() - Clear Stored Message
Example for callingclear
- Set up Dependencies and Define the ABI
- Configure the Contract Instance
- Prepare Function Parameters
- Send the Transaction
Nilify and Burn
These two functions exist in the Endpoint contract and are used in very specific cases to avoid malicious acts by DVNs. These two functions are infrequently utilized and serve as precautionary design measures.nilify() - Mark Message as Nil
Thenilify function is designed to transform a non-executed payload hash into NIL value (0xFFFFFF…). This transformation enables the resubmission of these NIL packets via the MessageLib back into the endpoint, providing a recovery mechanism from disruptions caused by malicious DVNs.
burn() - Permanently Block Message
Theburn function operates similarly to the clear function with two key distinctions:
- The OApp is not required to be aware of the original payload
- The nonce designated for burning must be less than the
lazyInboundNonce