From a087c47668a702f1a1b762c99580d99dcb3f5837 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Tue, 30 Aug 2022 10:30:19 +0200 Subject: [PATCH] Account for full transaction encoding when batching messages (#2575) * Remove a useless clone * De-clone estimate_tx_fees * cosmos: More de-owning around sign_and_encode_tx * Simplify prepending of ClientUpdate * cosmos: encoded_tx_len function The function evaluates the length of an encoded transaction, to perform more accurate batching. * Account for field encoding in tx batch size * Account for tx envelope in message batching * More credible test fixture for batch_messages * Fix calculations in batch_messages, adjust tests * Initialize KeyEntry data from a seed file * relayer: module chain::cosmos::test_utils Move utilities from chain::cosmos::batch to share them with other modules' unit tests. * Take tx_body varint lenth delimiter into account In batch_messages, the varint encoding of the length of the tx_body field of TxRaw may increase the length of the envelope as the body size grows. * Account for body encoding when batching messages The tx_body member of TxRaw encodes more than the messages, so its total length needs to be taken into account when estimating the total transaction size from the previously computed envelope and the vector of messages. * Document EncodedTxMetrics * Revert "relayer: module chain::cosmos::test_utils" This reverts commit 6a8e31f7d150f0596ddad73a87ef05a6ffd38af3. * batch: fix size estimation for empty body When the TxBody struct is completely empty (all fields have default values), it is encoded as an empty array and the body_bytes field is then also omitted from the encoding of TxRaw. Add transaction size verification to the unit tests of batch_messages, by creating encoded tx from the batched messages (using the maximum fee to keep unit tests simple) and checking the size corresponds to the `MaxTxSize` parameter. * Improve batch_does_not_exceed_max_tx_size test Test larger numbers of messages, up to 100 (maximum allowed per MaxMsgNum limits), with length increasing in the arithmetic progression. For each round, make sure that the size limit is just equal to the size of an encoded tx with all messages except the last one. Verify that the last message is spilled into the next batch and the resulting tx size for the first batch equals the limit. * Remove an unnecessary branch * Add changelog entry Co-authored-by: Romain Ruetschi --- .../ibc-relayer/2575-tx-size-encoding.md | 2 + relayer/src/chain/cosmos/batch.rs | 280 ++++++++++++++---- relayer/src/chain/cosmos/encode.rs | 45 ++- relayer/src/chain/cosmos/estimate.rs | 2 +- relayer/src/chain/cosmos/retry.rs | 4 +- relayer/src/chain/cosmos/tx.rs | 6 +- relayer/src/config/types.rs | 3 +- relayer/src/error.rs | 4 +- relayer/src/link/operational_data.rs | 11 +- .../tests/config/fixtures/relayer-seed.json | 7 + tools/test-framework/src/relayer/tx.rs | 2 +- 11 files changed, 295 insertions(+), 71 deletions(-) create mode 100644 .changelog/unreleased/improvements/ibc-relayer/2575-tx-size-encoding.md create mode 100644 relayer/tests/config/fixtures/relayer-seed.json diff --git a/.changelog/unreleased/improvements/ibc-relayer/2575-tx-size-encoding.md b/.changelog/unreleased/improvements/ibc-relayer/2575-tx-size-encoding.md new file mode 100644 index 0000000000..d82d64e5d5 --- /dev/null +++ b/.changelog/unreleased/improvements/ibc-relayer/2575-tx-size-encoding.md @@ -0,0 +1,2 @@ +- Account for full transaction encoding when batching messages + ([#2575](https://github.com/informalsystems/ibc-rs/issues/2575)) \ No newline at end of file diff --git a/relayer/src/chain/cosmos/batch.rs b/relayer/src/chain/cosmos/batch.rs index f519a2c296..c51a3ec73f 100644 --- a/relayer/src/chain/cosmos/batch.rs +++ b/relayer/src/chain/cosmos/batch.rs @@ -8,6 +8,8 @@ use prost::Message; use tendermint_rpc::endpoint::broadcast::tx_sync::Response; use tracing::debug; +use crate::chain::cosmos::encode::encoded_tx_metrics; +use crate::chain::cosmos::gas::gas_amount_to_fee; use crate::chain::cosmos::retry::send_tx_with_account_sequence_retry; use crate::chain::cosmos::types::account::Account; use crate::chain::cosmos::types::config::TxConfig; @@ -116,7 +118,15 @@ pub async fn send_batched_messages_and_wait_check_tx( return Ok(Vec::new()); } - let batches = batch_messages(max_msg_num, max_tx_size, messages)?; + let batches = batch_messages( + config, + max_msg_num, + max_tx_size, + key_entry, + account, + tx_memo, + messages, + )?; let mut responses = Vec::new(); @@ -145,7 +155,15 @@ async fn send_messages_as_batches( let message_count = messages.len(); - let batches = batch_messages(max_msg_num, max_tx_size, messages)?; + let batches = batch_messages( + config, + max_msg_num, + max_tx_size, + key_entry, + account, + tx_memo, + messages, + )?; debug!( "sending {} messages as {} batches to chain {} in parallel", @@ -185,7 +203,15 @@ async fn sequential_send_messages_as_batches( let message_count = messages.len(); - let batches = batch_messages(max_msg_num, max_tx_size, messages)?; + let batches = batch_messages( + config, + max_msg_num, + max_tx_size, + key_entry, + account, + tx_memo, + messages, + )?; debug!( "sending {} messages as {} batches to chain {} in serial", @@ -249,8 +275,12 @@ fn response_to_tx_sync_result( } fn batch_messages( + config: &TxConfig, max_msg_num: MaxMsgNum, max_tx_size: MaxTxSize, + key_entry: &KeyEntry, + account: &Account, + tx_memo: &Memo, messages: Vec, ) -> Result>, Error> { let max_message_count = max_msg_num.to_usize(); @@ -258,32 +288,51 @@ fn batch_messages( let mut batches = vec![]; + // Estimate the overhead of the transaction envelope's encoding, + // by taking the encoded length of an empty tx with the same auth info and signatures. + // Use the maximum possible fee to get an upper bound for varint encoding. + let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + let tx_metrics = encoded_tx_metrics(config, key_entry, account, tx_memo, &[], &max_fee)?; + let tx_envelope_len = tx_metrics.envelope_len; + let empty_body_len = tx_metrics.body_bytes_len; + + // Full length of the transaction can then be derived from the length of the invariable + // envelope and the length of the body field, taking into account the varint encoding + // of the body field's length delimiter. + fn tx_len(envelope_len: usize, body_len: usize) -> usize { + // The caller has at least one message field length added to the body's + debug_assert!(body_len != 0); + envelope_len + 1 + prost::length_delimiter_len(body_len) + body_len + } + let mut current_count = 0; - let mut current_size = 0; + let mut current_len = empty_body_len; let mut current_batch = vec![]; for message in messages { let message_len = message.encoded_len(); - if message_len > max_tx_size { - return Err(Error::message_exceeds_max_tx_size(message_len)); - } + // The total length the message adds to the encoding includes the + // field tag (small varint) and the length delimiter. + let tagged_len = 1 + prost::length_delimiter_len(message_len) + message_len; - if current_count >= max_message_count || current_size + message_len > max_tx_size { + if current_count >= max_message_count + || tx_len(tx_envelope_len, current_len + tagged_len) > max_tx_size + { let insert_batch = mem::take(&mut current_batch); - assert!( - !insert_batch.is_empty(), - "max message count should not be 0" - ); + if insert_batch.is_empty() { + assert!(max_message_count != 0); + return Err(Error::message_too_big_for_tx(message_len)); + } batches.push(insert_batch); current_count = 0; - current_size = 0; + current_len = empty_body_len; } current_count += 1; - current_size += message_len; + current_len += tagged_len; current_batch.push(message); } @@ -297,50 +346,121 @@ fn batch_messages( #[cfg(test)] mod tests { use super::batch_messages; - use crate::config::types::{MaxMsgNum, MaxTxSize}; + use crate::chain::cosmos::encode::sign_and_encode_tx; + use crate::chain::cosmos::gas::gas_amount_to_fee; + use crate::chain::cosmos::types::account::{Account, AccountNumber, AccountSequence}; + use crate::chain::cosmos::types::config::TxConfig; + use crate::config; + use crate::config::types::{MaxMsgNum, MaxTxSize, Memo}; + use crate::keyring::{self, KeyEntry, KeyRing}; + use ibc::core::ics24_host::identifier::ChainId; use ibc_proto::google::protobuf::Any; + use std::fs; + + const COSMOS_HD_PATH: &str = "m/44'/118'/0'/0/0"; + + fn test_fixture() -> (TxConfig, KeyEntry, Account) { + let path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/config/fixtures/relayer_conf_example.toml" + ); + let config = config::load(path).expect("could not parse config"); + let chain_id = ChainId::from_string("chain_A"); + let chain_config = config.find_chain(&chain_id).unwrap(); + + let tx_config = TxConfig::try_from(chain_config).expect("could not obtain tx config"); + + let path = concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/config/fixtures/relayer-seed.json" + ); + let seed_file_content = fs::read_to_string(path).unwrap(); + let keyring = KeyRing::new(keyring::Store::Memory, "cosmos", &chain_id).unwrap(); + let hd_path = COSMOS_HD_PATH.parse().unwrap(); + let key_entry = keyring + .key_from_seed_file(&seed_file_content, &hd_path) + .unwrap(); + + let account = Account { + number: AccountNumber::new(0), + sequence: AccountSequence::new(0), + }; + + (tx_config, key_entry, account) + } #[test] fn batch_does_not_exceed_max_tx_size() { - let messages = vec![ - Any { - type_url: "/example.Foo".into(), - value: vec![0; 6], - }, - Any { - type_url: "/example.Bar".into(), - value: vec![0; 4], - }, - Any { - type_url: "/example.Baz".into(), - value: vec![0; 2], - }, - ]; - let batches = - batch_messages(MaxMsgNum::default(), MaxTxSize::new(42).unwrap(), messages).unwrap(); - - assert_eq!(batches.len(), 2); - assert_eq!(batches[0].len(), 2); - assert_eq!(batches[0][0].type_url, "/example.Foo"); - assert_eq!(batches[0][0].value.len(), 6); - assert_eq!(batches[0][1].type_url, "/example.Bar"); - assert_eq!(batches[0][1].value.len(), 4); - - assert_eq!(batches[1].len(), 1); - assert_eq!(batches[1][0].type_url, "/example.Baz"); - assert_eq!(batches[1][0].value.len(), 2); + let (config, key_entry, account) = test_fixture(); + let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + let mut messages = vec![Any { + type_url: "/example.Baz".into(), + value: vec![0; 2], + }]; + let memo = Memo::new("").unwrap(); + for n in 0..100 { + messages.insert( + messages.len() - 1, + Any { + type_url: "/example.Foo".into(), + value: vec![0; n], + }, + ); + let expected_batch_len = messages.len() - 1; + let tx_bytes = sign_and_encode_tx( + &config, + &key_entry, + &account, + &memo, + &messages[..expected_batch_len], + &max_fee, + ) + .unwrap(); + let max_tx_size = MaxTxSize::new(tx_bytes.len()).unwrap(); + + let batches = batch_messages( + &config, + MaxMsgNum::new(100).unwrap(), + max_tx_size, + &key_entry, + &account, + &memo, + messages.clone(), + ) + .unwrap(); + + assert_eq!(batches.len(), 2); + assert_eq!(batches[0].len(), expected_batch_len); + + let tx_bytes = + sign_and_encode_tx(&config, &key_entry, &account, &memo, &batches[0], &max_fee) + .unwrap(); + assert_eq!(tx_bytes.len(), max_tx_size.to_usize()); + + assert_eq!(batches[1].len(), 1); + assert_eq!(batches[1][0].type_url, "/example.Baz"); + assert_eq!(batches[1][0].value.len(), 2); + } } #[test] fn batch_error_on_oversized_message() { + const MAX_TX_SIZE: usize = 203; + + let (config, key_entry, account) = test_fixture(); let messages = vec![Any { type_url: "/example.Foo".into(), value: vec![0; 6], }]; + let memo = Memo::new("example").unwrap(); let batches = batch_messages( + &config, MaxMsgNum::default(), - MaxTxSize::new(22).unwrap(), + MaxTxSize::new(MAX_TX_SIZE).unwrap(), + &key_entry, + &account, + &memo, messages.clone(), ) .unwrap(); @@ -348,13 +468,28 @@ mod tests { assert_eq!(batches.len(), 1); assert_eq!(batches[0].len(), 1); - let res = batch_messages(MaxMsgNum::default(), MaxTxSize::new(21).unwrap(), messages); + let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + let tx_bytes = + sign_and_encode_tx(&config, &key_entry, &account, &memo, &batches[0], &max_fee) + .unwrap(); + assert_eq!(tx_bytes.len(), MAX_TX_SIZE); + + let res = batch_messages( + &config, + MaxMsgNum::default(), + MaxTxSize::new(MAX_TX_SIZE - 1).unwrap(), + &key_entry, + &account, + &memo, + messages, + ); assert!(res.is_err()); } #[test] fn test_batches_are_structured_appropriately_per_max_msg_num() { + let (config, key_entry, account) = test_fixture(); // Ensure that when MaxMsgNum is 1, the resulting batch // consists of 5 smaller batches, each with a single message let messages = vec![ @@ -381,8 +516,12 @@ mod tests { ]; let batches = batch_messages( + &config, MaxMsgNum::new(1).unwrap(), MaxTxSize::default(), + &key_entry, + &account, + &Memo::new("").unwrap(), messages.clone(), ) .unwrap(); @@ -395,8 +534,16 @@ mod tests { // Ensure that when MaxMsgNum > the number of messages, the resulting // batch consists of a single smaller batch with all of the messages - let batches = - batch_messages(MaxMsgNum::new(100).unwrap(), MaxTxSize::default(), messages).unwrap(); + let batches = batch_messages( + &config, + MaxMsgNum::new(100).unwrap(), + MaxTxSize::default(), + &key_entry, + &account, + &Memo::new("").unwrap(), + messages, + ) + .unwrap(); assert_eq!(batches.len(), 1); assert_eq!(batches[0].len(), 5); @@ -404,8 +551,11 @@ mod tests { #[test] fn test_batches_are_structured_appropriately_per_max_tx_size() { - // Ensure that when MaxTxSize == the size of each message, the resulting batch - // consists of 5 smaller batches, each with a single message + const MAX_TX_SIZE: usize = 198; + + let (config, key_entry, account) = test_fixture(); + // Ensure that when MaxTxSize is only enough to fit each one of the messages, + // the resulting batch consists of 5 smaller batches, each with a single message. let messages = vec![ Any { type_url: "/example.Foo".into(), @@ -428,24 +578,43 @@ mod tests { value: vec![0; 10], }, ]; + let memo = Memo::new("").unwrap(); let batches = batch_messages( + &config, MaxMsgNum::default(), - MaxTxSize::new(26).unwrap(), + MaxTxSize::new(MAX_TX_SIZE).unwrap(), + &key_entry, + &account, + &memo, messages.clone(), ) .unwrap(); assert_eq!(batches.len(), 5); + let max_fee = gas_amount_to_fee(&config.gas_config, config.gas_config.max_gas); + for batch in batches { assert_eq!(batch.len(), 1); + let tx_bytes = + sign_and_encode_tx(&config, &key_entry, &account, &memo, &batch, &max_fee).unwrap(); + assert_eq!(tx_bytes.len(), MAX_TX_SIZE); } // Ensure that when MaxTxSize > the size of all the messages, the // resulting batch consists of a single smaller batch with all of // messages inside - let batches = batch_messages(MaxMsgNum::default(), MaxTxSize::max(), messages).unwrap(); + let batches = batch_messages( + &config, + MaxMsgNum::default(), + MaxTxSize::max(), + &key_entry, + &account, + &Memo::new("").unwrap(), + messages, + ) + .unwrap(); assert_eq!(batches.len(), 1); assert_eq!(batches[0].len(), 5); @@ -454,6 +623,15 @@ mod tests { #[test] #[should_panic(expected = "`max_msg_num` must be greater than or equal to 1, found 0")] fn test_max_msg_num_of_zero_panics() { - let _batches = batch_messages(MaxMsgNum::new(0).unwrap(), MaxTxSize::default(), vec![]); + let (config, key_entry, account) = test_fixture(); + let _batches = batch_messages( + &config, + MaxMsgNum::new(0).unwrap(), + MaxTxSize::default(), + &key_entry, + &account, + &Memo::new("").unwrap(), + vec![], + ); } } diff --git a/relayer/src/chain/cosmos/encode.rs b/relayer/src/chain/cosmos/encode.rs index d804c7adc9..181892336b 100644 --- a/relayer/src/chain/cosmos/encode.rs +++ b/relayer/src/chain/cosmos/encode.rs @@ -4,6 +4,7 @@ use ibc::core::ics24_host::identifier::ChainId; use ibc_proto::cosmos::tx::v1beta1::mode_info::{Single, Sum}; use ibc_proto::cosmos::tx::v1beta1::{AuthInfo, Fee, ModeInfo, SignDoc, SignerInfo, TxBody, TxRaw}; use ibc_proto::google::protobuf::Any; +use prost::Message; use tendermint::account::Id as AccountId; use crate::chain::cosmos::types::account::{Account, AccountNumber, AccountSequence}; @@ -19,7 +20,7 @@ pub fn sign_and_encode_tx( key_entry: &KeyEntry, account: &Account, tx_memo: &Memo, - messages: Vec, + messages: &[Any], fee: &Fee, ) -> Result, Error> { let signed_tx = sign_tx(config, key_entry, account, tx_memo, messages, fee)?; @@ -33,12 +34,50 @@ pub fn sign_and_encode_tx( encode_tx_raw(tx_raw) } +/// Length information for an encoded transaction. +pub struct EncodedTxMetrics { + /// Length of the encoded message, excluding the `body_bytes` field. + pub envelope_len: usize, + /// Length of the byte array in the `body_bytes` field of the `TxRaw` message. + pub body_bytes_len: usize, +} + +pub fn encoded_tx_metrics( + config: &TxConfig, + key_entry: &KeyEntry, + account: &Account, + tx_memo: &Memo, + messages: &[Any], + fee: &Fee, +) -> Result { + let signed_tx = sign_tx(config, key_entry, account, tx_memo, messages, fee)?; + + let tx_raw = TxRaw { + body_bytes: signed_tx.body_bytes, + auth_info_bytes: signed_tx.auth_info_bytes, + signatures: signed_tx.signatures, + }; + + let total_len = tx_raw.encoded_len(); + let body_bytes_len = tx_raw.body_bytes.len(); + let envelope_len = if body_bytes_len == 0 { + total_len + } else { + total_len - 1 - prost::length_delimiter_len(body_bytes_len) - body_bytes_len + }; + + Ok(EncodedTxMetrics { + envelope_len, + body_bytes_len, + }) +} + pub fn sign_tx( config: &TxConfig, key_entry: &KeyEntry, account: &Account, tx_memo: &Memo, - messages: Vec, + messages: &[Any], fee: &Fee, ) -> Result { let key_bytes = encode_key_bytes(key_entry)?; @@ -161,7 +200,7 @@ fn auth_info_and_bytes(signer_info: SignerInfo, fee: Fee) -> Result<(AuthInfo, V } fn tx_body_and_bytes( - proto_msgs: Vec, + proto_msgs: &[Any], memo: &Memo, extension_options: Vec, ) -> Result<(TxBody, Vec), Error> { diff --git a/relayer/src/chain/cosmos/estimate.rs b/relayer/src/chain/cosmos/estimate.rs index 9764598a2c..c05b937c0f 100644 --- a/relayer/src/chain/cosmos/estimate.rs +++ b/relayer/src/chain/cosmos/estimate.rs @@ -19,7 +19,7 @@ pub async fn estimate_tx_fees( key_entry: &KeyEntry, account: &Account, tx_memo: &Memo, - messages: Vec, + messages: &[Any], ) -> Result { let gas_config = &config.gas_config; diff --git a/relayer/src/chain/cosmos/retry.rs b/relayer/src/chain/cosmos/retry.rs index d9b572a50c..a890b89fb9 100644 --- a/relayer/src/chain/cosmos/retry.rs +++ b/relayer/src/chain/cosmos/retry.rs @@ -69,7 +69,7 @@ async fn refresh_account_and_retry_send_tx_with_account_sequence( refresh_account(&config.grpc_address, &key_entry.account, account).await?; // Retry after delay. thread::sleep(Duration::from_millis(ACCOUNT_SEQUENCE_RETRY_DELAY)); - estimate_fee_and_send_tx(config, key_entry, account, tx_memo, messages.clone()).await + estimate_fee_and_send_tx(config, key_entry, account, tx_memo, &messages).await } async fn do_send_tx_with_account_sequence_retry( @@ -79,7 +79,7 @@ async fn do_send_tx_with_account_sequence_retry( tx_memo: &Memo, messages: Vec, ) -> Result { - match estimate_fee_and_send_tx(config, key_entry, account, tx_memo, messages.clone()).await { + match estimate_fee_and_send_tx(config, key_entry, account, tx_memo, &messages).await { // Gas estimation failed with acct. s.n. mismatch at estimate gas step. // It indicates that the account sequence cached by hermes is stale (got < expected). // This can happen when the same account is used by another agent. diff --git a/relayer/src/chain/cosmos/tx.rs b/relayer/src/chain/cosmos/tx.rs index e6a0519e1f..4b78789e04 100644 --- a/relayer/src/chain/cosmos/tx.rs +++ b/relayer/src/chain/cosmos/tx.rs @@ -16,9 +16,9 @@ pub async fn estimate_fee_and_send_tx( key_entry: &KeyEntry, account: &Account, tx_memo: &Memo, - messages: Vec, + messages: &[Any], ) -> Result { - let fee = estimate_tx_fees(config, key_entry, account, tx_memo, messages.clone()).await?; + let fee = estimate_tx_fees(config, key_entry, account, tx_memo, messages).await?; send_tx_with_fee(config, key_entry, account, tx_memo, messages, &fee).await } @@ -28,7 +28,7 @@ async fn send_tx_with_fee( key_entry: &KeyEntry, account: &Account, tx_memo: &Memo, - messages: Vec, + messages: &[Any], fee: &Fee, ) -> Result { let tx_bytes = sign_and_encode_tx(config, key_entry, account, tx_memo, messages, fee)?; diff --git a/relayer/src/config/types.rs b/relayer/src/config/types.rs index 9d46f70948..00346505a5 100644 --- a/relayer/src/config/types.rs +++ b/relayer/src/config/types.rs @@ -199,7 +199,8 @@ pub mod memo { impl Memo { const MAX_LEN: usize = 50; - pub fn new(memo: String) -> Result { + pub fn new(memo: impl Into) -> Result { + let memo = memo.into(); if memo.len() > Self::MAX_LEN { return Err(Error::too_long(memo.len())); } diff --git a/relayer/src/error.rs b/relayer/src/error.rs index 10066aee1d..283ab6f3de 100644 --- a/relayer/src/error.rs +++ b/relayer/src/error.rs @@ -521,10 +521,10 @@ define_error! { "Query/DenomTrace RPC returned an empty denom trace for trace hash: {}", e.hash) }, - MessageExceedsMaxTxSize + MessageTooBigForTx { len: usize } |e| { - format_args!("message length {} exceeds maximum transaction size", e.len) + format_args!("message with length {} is too large for a transaction", e.len) } } } diff --git a/relayer/src/link/operational_data.rs b/relayer/src/link/operational_data.rs index b3767fbaf4..621f7db199 100644 --- a/relayer/src/link/operational_data.rs +++ b/relayer/src/link/operational_data.rs @@ -1,5 +1,4 @@ use core::fmt; -use core::iter; use std::time::{Duration, Instant}; use ibc_proto::google::protobuf::Any; @@ -211,12 +210,10 @@ impl OperationalData { } }; - let msgs: Vec = match client_update_msg { - Some(client_update) => iter::once(client_update) - .chain(self.batch.iter().map(|gm| gm.msg.clone())) - .collect(), - None => self.batch.iter().map(|gm| gm.msg.clone()).collect(), - }; + let msgs = client_update_msg + .into_iter() + .chain(self.batch.iter().map(|gm| gm.msg.clone())) + .collect(); let tm = TrackedMsgs::new(msgs, self.tracking_id); diff --git a/relayer/tests/config/fixtures/relayer-seed.json b/relayer/tests/config/fixtures/relayer-seed.json new file mode 100644 index 0000000000..4dad31a216 --- /dev/null +++ b/relayer/tests/config/fixtures/relayer-seed.json @@ -0,0 +1,7 @@ +{ + "name": "relayer-584b9db9", + "type": "local", + "address": "cosmos1dvu2zm4vzma30q403d0ezww3wpl7wcpp0nhcph", + "pubkey": "{\"@type\":\"/cosmos.crypto.secp256k1.PubKey\",\"key\":\"A5W0C7iEAuonX56sR81PiwaKTE0GvZlCYuGwHTMpWJo+\"}", + "mnemonic": "such walnut usual noble image raise cabin suspect combine key absurd detail present bless yard grief amazing slam brown donate fabric opera desk minor" +} \ No newline at end of file diff --git a/tools/test-framework/src/relayer/tx.rs b/tools/test-framework/src/relayer/tx.rs index c54d9e9bb6..d1f3204183 100644 --- a/tools/test-framework/src/relayer/tx.rs +++ b/tools/test-framework/src/relayer/tx.rs @@ -99,7 +99,7 @@ pub async fn simple_send_tx( let message_count = messages.len(); let response = - estimate_fee_and_send_tx(config, key_entry, &account, &Default::default(), messages) + estimate_fee_and_send_tx(config, key_entry, &account, &Default::default(), &messages) .await?; let tx_sync_result = TxSyncResult {