Reversed execution order of post-dispatch hooks
Description
In Hyperlane, a Mailbox is configured with the following two post-dispatch hooks:
required
: This hook is always invoked on everydispatch
call, along with the value that covers the required fee.
default
: This hook can be overridden by the caller, and is invoked after therequired
hook, with the remaining value.
In the current version, the execution of these hooks is implemented as follows:
let default_hook = hook.or(self.default_hook);
if let Some(default_hook) = default_hook {
let result = ScryptoVmV1Api::object_call(
default_hook.as_node_id(),
"post_dispatch",
scrypto_args!(hook_metadata.clone(), hyperlane_message.clone(), payment),
);
payment = scrypto_decode(&result)
.expect(&format_error!("failed to decode post_dispatch result"));
}
if let Some(required_hook) = self.required_hook {
let result = ScryptoVmV1Api::object_call(
required_hook.as_node_id(),
"post_dispatch",
scrypto_args!(hook_metadata, hyperlane_message.clone(), payment),
);
payment = scrypto_decode(&result)
.expect(&format_error!("failed to decode post_dispatch result"));
}
As shown above, the default_hook
- whether it is provided by the caller or the configured default hook - is executed before the required_hook
.
Impact
If resources are consumed during the execution of the default
hook, the required
hook may fail due to insufficient resources, potentially causing the transaction to revert. Furthermore, this behavior represents a mismatch between the actual implementation and the execution order of the two hooks that is specified in the Hyperlane protocol documentation, and may cause confusion for users.
Recommendations
Modify the dispatch
function so that the execution of self.required_hook
precedes that of the default_hook
.
Remediation
This issue has been acknowledged by Hyperlane, and a fix was implemented in commit 791c65c6↗.