feat: use batching configs on all execution environments (#3723)

### Description

While we only have a tx batching implementation available for EVM
chains, we still parallelize the `prepare` and `confirm` steps in the
serial submitter according to the `maxBatchSize` config item. To reap
the benefits of this change, we need to make these configs universal,
because they were only defined within `h_eth::ChainConnectionConf`.

This PR adds slight duplication because it adds the batching config on
each individual connection config, but it's far simpler than including
it in the `ChainConf` struct. The latter would've required changing all
the trait impls of `BuildableWithProvider` to include the batching
config.

### Drive-by changes

Renames `serial_submitter` to `op_submitter` since it's no longer
serial.

### Related issues

Fixes https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/3722

### Backward compatibility

Yes

### Testing

Manually - added the configs to cosmos e2e and checked the logs
pull/3748/head
Daniel Savu 7 months ago committed by GitHub
parent f46cf7708e
commit be43b0fd91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      rust/agents/relayer/src/msg/mod.rs
  2. 0
      rust/agents/relayer/src/msg/op_submitter.rs
  3. 2
      rust/agents/relayer/src/msg/processor.rs
  4. 4
      rust/agents/relayer/src/relayer.rs
  5. 7
      rust/chains/hyperlane-cosmos/src/trait_builder.rs
  6. 15
      rust/chains/hyperlane-ethereum/src/config.rs
  7. 2
      rust/chains/hyperlane-ethereum/src/contracts/mailbox.rs
  8. 4
      rust/chains/hyperlane-ethereum/src/contracts/multicall.rs
  9. 4
      rust/chains/hyperlane-sealevel/src/trait_builder.rs
  10. 10
      rust/hyperlane-base/src/settings/chains.rs
  11. 42
      rust/hyperlane-base/src/settings/parser/connection_parser.rs
  12. 16
      rust/hyperlane-base/src/settings/parser/mod.rs
  13. 11
      rust/hyperlane-core/src/config/mod.rs
  14. 2
      rust/utils/run-locally/src/cosmos/mod.rs
  15. 4
      typescript/infra/config/environments/mainnet3/agent.ts

@ -28,7 +28,7 @@
pub(crate) mod gas_payment;
pub(crate) mod metadata;
pub(crate) mod op_queue;
pub(crate) mod op_submitter;
pub(crate) mod pending_message;
pub(crate) mod pending_operation;
pub(crate) mod processor;
pub(crate) mod serial_submitter;

@ -242,7 +242,7 @@ mod test {
url: "http://example.com".parse().unwrap(),
},
transaction_overrides: Default::default(),
message_batch: Default::default(),
operation_batch: Default::default(),
}),
metrics_conf: Default::default(),
index: Default::default(),

@ -33,9 +33,9 @@ use crate::{
gas_payment::GasPaymentEnforcer,
metadata::{BaseMetadataBuilder, IsmAwareAppContextClassifier},
op_queue::QueueOperation,
op_submitter::{SerialSubmitter, SerialSubmitterMetrics},
pending_message::{MessageContext, MessageSubmissionMetrics},
processor::{MessageProcessor, MessageProcessorMetrics},
serial_submitter::{SerialSubmitter, SerialSubmitterMetrics},
},
server::{self as relayer_server, MessageRetryRequest},
settings::{matching_list::MatchingList, RelayerSettings},
@ -315,7 +315,7 @@ impl BaseAgent for Relayer {
// Default to submitting one message at a time if there is no batch config
self.core.settings.chains[dest_domain.name()]
.connection
.message_batch_config()
.operation_batch_config()
.map(|c| c.max_batch_size)
.unwrap_or(1),
),

@ -1,7 +1,7 @@
use std::str::FromStr;
use derive_new::new;
use hyperlane_core::{ChainCommunicationError, FixedPointNumber};
use hyperlane_core::{config::OperationBatchConfig, ChainCommunicationError, FixedPointNumber};
use url::Url;
/// Cosmos connection configuration
@ -25,6 +25,8 @@ pub struct ConnectionConf {
/// Cosmos address lengths are sometimes less than 32 bytes, so this helps to serialize it in
/// bech32 with the appropriate length.
contract_address_bytes: usize,
/// Operation batching configuration
pub operation_batch: OperationBatchConfig,
}
/// Untyped cosmos amount
@ -112,6 +114,7 @@ impl ConnectionConf {
}
/// Create a new connection configuration
#[allow(clippy::too_many_arguments)]
pub fn new(
grpc_urls: Vec<Url>,
rpc_url: String,
@ -120,6 +123,7 @@ impl ConnectionConf {
canonical_asset: String,
minimum_gas_price: RawCosmosAmount,
contract_address_bytes: usize,
operation_batch: OperationBatchConfig,
) -> Self {
Self {
grpc_urls,
@ -129,6 +133,7 @@ impl ConnectionConf {
canonical_asset,
gas_price: minimum_gas_price,
contract_address_bytes,
operation_batch,
}
}
}

@ -1,4 +1,4 @@
use hyperlane_core::{H256, U256};
use hyperlane_core::{config::OperationBatchConfig, U256};
use url::Url;
/// Ethereum RPC connection configuration
@ -33,8 +33,8 @@ pub struct ConnectionConf {
pub rpc_connection: RpcConnectionConf,
/// Transaction overrides to use when sending transactions.
pub transaction_overrides: TransactionOverrides,
/// Message batching configuration
pub message_batch: MessageBatchConfig,
/// Operation batching configuration
pub operation_batch: OperationBatchConfig,
}
/// Ethereum transaction overrides.
@ -51,12 +51,3 @@ pub struct TransactionOverrides {
/// Max priority fee per gas to use for EIP-1559 transactions.
pub max_priority_fee_per_gas: Option<U256>,
}
/// Config for batching messages
#[derive(Debug, Clone, Default)]
pub struct MessageBatchConfig {
/// Optional Multicall3 contract address
pub multicall3_address: Option<H256>,
/// Batch size
pub max_batch_size: u32,
}

@ -504,7 +504,7 @@ mod test {
url: "http://127.0.0.1:8545".parse().unwrap(),
},
transaction_overrides: Default::default(),
message_batch: Default::default(),
operation_batch: Default::default(),
};
let mailbox = EthereumMailbox::new(

@ -14,8 +14,8 @@ pub async fn build_multicall<M: Middleware + 'static>(
domain: HyperlaneDomain,
) -> eyre::Result<Multicall<M>> {
let address = conn
.message_batch
.multicall3_address
.operation_batch
.batch_contract_address
.unwrap_or(hex_or_base58_to_h256("0xcA11bde05977b3631167028862bE2a173976CA11").unwrap());
let ethereum_provider = EthereumProvider::new(provider.clone(), domain);
if !ethereum_provider.is_contract(&address).await? {

@ -1,4 +1,4 @@
use hyperlane_core::ChainCommunicationError;
use hyperlane_core::{config::OperationBatchConfig, ChainCommunicationError};
use url::Url;
/// Sealevel connection configuration
@ -6,6 +6,8 @@ use url::Url;
pub struct ConnectionConf {
/// Fully qualified string to connect to
pub url: Url,
/// Operation batching configuration
pub operation_batch: OperationBatchConfig,
}
/// An error type when parsing a connection configuration.

@ -7,8 +7,8 @@ use eyre::{eyre, Context, Result};
use ethers_prometheus::middleware::{ChainInfo, ContractInfo, PrometheusMiddlewareConf};
use hyperlane_core::{
AggregationIsm, CcipReadIsm, ContractLocator, HyperlaneAbi, HyperlaneDomain,
HyperlaneDomainProtocol, HyperlaneMessage, HyperlaneProvider, IndexMode,
config::OperationBatchConfig, AggregationIsm, CcipReadIsm, ContractLocator, HyperlaneAbi,
HyperlaneDomain, HyperlaneDomainProtocol, HyperlaneMessage, HyperlaneProvider, IndexMode,
InterchainGasPaymaster, InterchainGasPayment, InterchainSecurityModule, Mailbox,
MerkleTreeHook, MerkleTreeInsertion, MultisigIsm, RoutingIsm, SequenceAwareIndexer,
ValidatorAnnounce, H256,
@ -127,9 +127,11 @@ impl ChainConnectionConf {
}
/// Get the message batch configuration for this chain.
pub fn message_batch_config(&self) -> Option<&h_eth::MessageBatchConfig> {
pub fn operation_batch_config(&self) -> Option<&OperationBatchConfig> {
match self {
Self::Ethereum(conf) => Some(&conf.message_batch),
Self::Ethereum(conf) => Some(&conf.operation_batch),
Self::Cosmos(conf) => Some(&conf.operation_batch),
Self::Sealevel(conf) => Some(&conf.operation_batch),
_ => None,
}
}

@ -1,6 +1,6 @@
use eyre::eyre;
use h_eth::TransactionOverrides;
use hyperlane_core::config::ConfigErrResultExt;
use hyperlane_core::config::{ConfigErrResultExt, OperationBatchConfig};
use hyperlane_core::{config::ConfigParsingError, HyperlaneDomainProtocol};
use url::Url;
@ -14,6 +14,7 @@ pub fn build_ethereum_connection_conf(
chain: &ValueParser,
err: &mut ConfigParsingError,
default_rpc_consensus_type: &str,
operation_batch: OperationBatchConfig,
) -> Option<ChainConnectionConf> {
let Some(first_url) = rpcs.to_owned().clone().into_iter().next() else {
return None;
@ -64,25 +65,10 @@ pub fn build_ethereum_connection_conf(
})
.unwrap_or_default();
let multicall3_address = chain
.chain(err)
.get_opt_key("batchContractAddress")
.parse_address_hash()
.end();
let max_batch_size = chain
.chain(err)
.get_opt_key("maxBatchSize")
.parse_u32()
.unwrap_or(1);
Some(ChainConnectionConf::Ethereum(h_eth::ConnectionConf {
rpc_connection: rpc_connection_conf?,
transaction_overrides,
message_batch: h_eth::MessageBatchConfig {
multicall3_address,
max_batch_size,
},
operation_batch,
}))
}
@ -90,6 +76,7 @@ pub fn build_cosmos_connection_conf(
rpcs: &[Url],
chain: &ValueParser,
err: &mut ConfigParsingError,
operation_batch: OperationBatchConfig,
) -> Option<ChainConnectionConf> {
let mut local_err = ConfigParsingError::default();
let grpcs =
@ -159,6 +146,7 @@ pub fn build_cosmos_connection_conf(
canonical_asset.unwrap(),
gas_price.unwrap(),
contract_address_bytes.unwrap().try_into().unwrap(),
operation_batch,
)))
}
}
@ -169,18 +157,28 @@ pub fn build_connection_conf(
chain: &ValueParser,
err: &mut ConfigParsingError,
default_rpc_consensus_type: &str,
operation_batch: OperationBatchConfig,
) -> Option<ChainConnectionConf> {
match domain_protocol {
HyperlaneDomainProtocol::Ethereum => {
build_ethereum_connection_conf(rpcs, chain, err, default_rpc_consensus_type)
}
HyperlaneDomainProtocol::Ethereum => build_ethereum_connection_conf(
rpcs,
chain,
err,
default_rpc_consensus_type,
operation_batch,
),
HyperlaneDomainProtocol::Fuel => rpcs
.iter()
.next()
.map(|url| ChainConnectionConf::Fuel(h_fuel::ConnectionConf { url: url.clone() })),
HyperlaneDomainProtocol::Sealevel => rpcs.iter().next().map(|url| {
ChainConnectionConf::Sealevel(h_sealevel::ConnectionConf { url: url.clone() })
ChainConnectionConf::Sealevel(h_sealevel::ConnectionConf {
url: url.clone(),
operation_batch,
})
}),
HyperlaneDomainProtocol::Cosmos => build_cosmos_connection_conf(rpcs, chain, err),
HyperlaneDomainProtocol::Cosmos => {
build_cosmos_connection_conf(rpcs, chain, err, operation_batch)
}
}
}

@ -187,6 +187,18 @@ fn parse_chain(
.parse_address_hash()
.end();
let batch_contract_address = chain
.chain(&mut err)
.get_opt_key("batchContractAddress")
.parse_address_hash()
.end();
let max_batch_size = chain
.chain(&mut err)
.get_opt_key("maxBatchSize")
.parse_u32()
.unwrap_or(1);
cfg_unwrap_all!(&chain.cwp, err: [domain]);
let connection = build_connection_conf(
domain.domain_protocol(),
@ -194,6 +206,10 @@ fn parse_chain(
&chain,
&mut err,
default_rpc_consensus_type,
OperationBatchConfig {
batch_contract_address,
max_batch_size,
},
);
cfg_unwrap_all!(&chain.cwp, err: [connection, mailbox, interchain_gas_paymaster, validator_announce, merkle_tree_hook]);

@ -10,6 +10,8 @@ use eyre::Report;
pub use str_or_int::{StrOrInt, StrOrIntParseError};
pub use trait_ext::*;
use crate::H256;
mod config_path;
mod str_or_int;
mod trait_ext;
@ -20,6 +22,15 @@ pub type ConfigResult<T> = Result<T, ConfigParsingError>;
/// A no-op filter type.
pub type NoFilter = ();
/// Config for batching messages
#[derive(Debug, Clone, Default)]
pub struct OperationBatchConfig {
/// Optional batch contract address (e.g. Multicall3 on EVM chains)
pub batch_contract_address: Option<H256>,
/// Batch size
pub max_batch_size: u32,
}
/// A trait that allows for constructing `Self` from a raw config type.
pub trait FromRawConf<T, F = NoFilter>: Sized
where

@ -294,6 +294,8 @@ fn launch_cosmos_relayer(
.hyp_env("RELAYCHAINS", relay_chains.join(","))
.hyp_env("DB", relayer_base.as_ref().to_str().unwrap())
.hyp_env("ALLOWLOCALCHECKPOINTSYNCERS", "true")
.hyp_env("CHAINS_COSMOSTEST99990_MAXBATCHSIZE", "5")
.hyp_env("CHAINS_COSMOSTEST99991_MAXBATCHSIZE", "5")
.hyp_env("TRACING_LEVEL", if debug { "debug" } else { "info" })
.hyp_env("GASPAYMENTENFORCEMENT", "[{\"type\": \"none\"}]")
.hyp_env("METRICSPORT", metrics.to_string())

@ -202,7 +202,7 @@ const hyperlane: RootAgentConfig = {
rpcConsensusType: RpcConsensusType.Fallback,
docker: {
repo,
tag: '1b8183e-20240503-174459',
tag: '3012392-20240507-130024',
},
gasPaymentEnforcement: gasPaymentEnforcement,
metricAppContexts,
@ -233,7 +233,7 @@ const releaseCandidate: RootAgentConfig = {
rpcConsensusType: RpcConsensusType.Fallback,
docker: {
repo,
tag: '1b8183e-20240503-174459',
tag: '3012392-20240507-130024',
},
// We're temporarily (ab)using the RC relayer as a way to increase
// message throughput.

Loading…
Cancel
Save