Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Gas Policy Minimum Handling to Prevent Unexpected Behavior #5517

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

christianangelopoulos
Copy link

Description

Prior to this change, configuring the gaspaymentenforcement parameter in the config to a minimum of 0 resulted in unexpected behavior. With this configuration, the relayer would relay any message from the designated relay chains, whether or not the message paid the specified IGP, resulting in the same behavior as gaspaymentenforcement of None.

This is due to fn message_meets_gas_payment_requirement in rust/main/agents/relayer/src/msg/gas_payment/mod.rs.

        let current_payment_option = self
            .db
            .retrieve_gas_payment_by_gas_payment_key(gas_payment_key)?;

        let current_payment = match current_payment_option {
            Some(payment) => payment,
            None => InterchainGasPayment::from_gas_payment_key(gas_payment_key),
        };
        

If the payment does not exist (because it was not indexed on the specified IGP), current_payment is set to InterchainGasPayment::from_gas_payment_key(gas_payment_key) which creates an InterchainGasPayment with a default payment value of 0. As a result, payments to other IGPs appeared to be 0 payments to the specified IGP. Therefore, in the loop later in the function, the message matches with GasPolicyStatus::PolicyMet(gas_limit) and the relayer relays it.

            return policy
                .message_meets_gas_payment_requirement(
                    message,
                    &current_payment,
                    &current_expenditure,
                    tx_cost_estimate,
                )
                .await
                .map(|result| {
                    if let Some(gas_limit) = result {
                        GasPolicyStatus::PolicyMet(gas_limit)
                    } else if current_payment_option.is_some() {
                        // There is a gas payment but it didn't meet the policy
                        GasPolicyStatus::PolicyNotMet
                    } else {
                        // No payment was found and it didn't meet the policy
                        GasPolicyStatus::NoPaymentFound
                    }
                });

These changes create the desired behavior, namely, that setting gaspaymentenforcement to a minimum of 0 should only relay messages that hooked / emitted from the specified IGP.

Changes

The desired functionality is implemented by modifying the message_meets_gas_payment_requirement function in rust/main/agents/relayer/src/msg/gas_payment/mod.rs. The change adds a check in that function to ensure that the self.db.retrieve_gas_payment_by_gas_payment_key(gas_payment_key)?; did in fact return a payment on the IGP from the database.

            if policy.requires_payment_found() && !payment_found {
                return Ok(GasPolicyStatus::NoPaymentFound);
            }

The check also calls a new function added to the GasPaymentPolicy trait called requires_payment_found. By default, this is set to return false, which allows the none.rs gas policy to skip this logic and continue relaying all messages. For the minimum.rs and on_chain_fee_quoting.rs gas policies, this is set to return true which requires a gas payment event to have been found on the specified IGP to continue.

Related issues

N/A

Backward compatibility

Unsure, as I am not as familiar with the history associated with this codebase.

Testing

Added unit tests and am currently running manual tests to ensure only messages that were emitted from the specified IGP were relayed.

Copy link

changeset-bot bot commented Feb 19, 2025

⚠️ No Changeset found

Latest commit: 89a8e7e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@shahrukhtrao
Copy link

shahrukhtrao commented Feb 19, 2025

@christianangelopoulos put fix: as prefix to pass linter

@christianangelopoulos christianangelopoulos changed the title Fix Gas Policy Minimum Handling to Prevent Unexpected Behavior fix: Gas Policy Minimum Handling to Prevent Unexpected Behavior Feb 19, 2025
@christianangelopoulos
Copy link
Author

added comments clarifying the requirements of each gas policy per request from @daniel-savu

Copy link
Contributor

@daniel-savu daniel-savu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great, thank you for taking the time to look into this! Left mostly nits

Comment on lines +502 to +511
payment: U256::from(1),
gas_amount: U256::from(1),
};
hyperlane_db.process_gas_payment(payment, &LogMeta::random());

let enforcer = GasPaymentEnforcer::new(
// Require a payment
vec![GasPaymentEnforcementConf {
policy: GasPaymentEnforcementPolicy::Minimum {
payment: U256::from(1),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we test for the zero payment edge case here since that's the goal of this PR. So with these params and some changes below as well, and the policy should still be met

Suggested change
payment: U256::from(1),
gas_amount: U256::from(1),
};
hyperlane_db.process_gas_payment(payment, &LogMeta::random());
let enforcer = GasPaymentEnforcer::new(
// Require a payment
vec![GasPaymentEnforcementConf {
policy: GasPaymentEnforcementPolicy::Minimum {
payment: U256::from(1),
payment: U256::zero(),
gas_amount: U256::zero(),
};
hyperlane_db.process_gas_payment(payment, &LogMeta::random());
let enforcer = GasPaymentEnforcer::new(
// Require a payment
vec![GasPaymentEnforcementConf {
policy: GasPaymentEnforcementPolicy::Minimum {
payment: U256::zero(),

let payment = InterchainGasPayment {
message_id: HyperlaneMessage::default().id(),
destination: HyperlaneMessage::default().destination,
payment: U256::from(100),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be anything so I'd set it to like 1 to make it easier to understand it's not related to the 100 in TxCostEstimate

message_id: HyperlaneMessage::default().id(),
destination: HyperlaneMessage::default().destination,
payment: U256::from(100),
gas_amount: U256::from(100),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the test uses a numerator of 1 and a denominator of 2 let's set this to 50 to test the edge case

Suggested change
gas_amount: U256::from(100),
gas_amount: U256::from(50),

Comment on lines +20 to +23
/// Minimum requires a message to exist on the IGP specified in the config,
/// even if the payment is zero. For example, a policy of Minimum { payment: 0 }
/// will only relay messages that are processed by the IGP specified in the config.
/// If you want to relay all messages regardless of payment and IGP, use `None`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
/// Minimum requires a message to exist on the IGP specified in the config,
/// even if the payment is zero. For example, a policy of Minimum { payment: 0 }
/// will only relay messages that are processed by the IGP specified in the config.
/// If you want to relay all messages regardless of payment and IGP, use `None`.
/// `Minimum` requires a payment to exist on the IGP specified in the config,
/// even if the payment is zero. For example, a policy of Minimum { payment: 0 }
/// will only relay messages that send a zero payment to the IGP specified in the config.
/// This is different from not requiring message senders to make any payment at all to the configured IGP to get relayed. To relay regardless of the existence of a payment, the `None` IGP policy should be used.


/// OnChainFeeQuoting requires the user to pay a specified fraction of the
/// estimated gas. Like the Minimum policy, OnChainFeeQuoting requires a
/// message to exist on the IGP specified in the config.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
/// message to exist on the IGP specified in the config.
/// payment to exist on the IGP specified in the config.

@@ -81,12 +81,17 @@ pub struct GasPaymentEnforcementConf {
#[derive(Debug, Clone, Default)]
pub enum GasPaymentEnforcementPolicy {
/// No requirement - all messages are processed regardless of gas payment
/// and regardless of whether the message was processed by the specified IGP.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
/// and regardless of whether the message was processed by the specified IGP.
/// and regardless of whether a payment for the message was processed by the specified IGP.

Comment on lines +89 to +90
/// even if the payment is zero. For example, a policy of Minimum { payment: 0 }
/// will only relay messages that are processed by the IGP specified in the config.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto as for message_meets_gas_payment_requirement

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In Review
Development

Successfully merging this pull request may close these issues.

3 participants